gpt4 book ai didi

scala - Scala trait 中的抽象私有(private)字段

转载 作者:行者123 更新时间:2023-12-04 13:27:53 24 4
gpt4 key购买 nike

我碰巧发现它不允许有抽象的私有(private)字段
一个特质,也就是说,

trait A1 {
//private val a: Int // Not allowed
protected val b: Int // OK
}

如果私有(private)字段,对抽象类做这样的事情似乎没问题
是构造函数参数,即
abstract class A2 (private val i: Int) // OK

所以我猜一个特征没有构造函数参数,所以没有
初始化它们的方式,因此不允许抽象私有(private)字段。

如果它们是“ protected ”,那么子类可以使用预初始化来初始化它们
字段。这种方法允许子类看到这些字段。

如果我只想初始化它们然后隐藏它们怎么办?
如下例所示?
object holding {
trait trick {
protected val seed: Int // Can't be private
final def magic: Int = seed + 123
}

trait new_trick extends trick {
def new_magic: Int = magic + 456
def the_seed: Int = seed // [1]
}

def play: new_trick = new { val seed = 1 } with new_trick

def show_seed(t: new_trick): Int = t.the_seed // [2]
}

希望任何人都能够看到种子,也就是说,不应该允许[2](因此[1])。
有没有办法让特质做到这一点?

正如@Randall 和@pagoda_5b 所指出的,我的问题没有多大意义
感觉。但幸运的是 @Régis 和 @axel22 把它变成了另一个有趣的
问题并提供了解决问题的模式。

最佳答案

在允许子特征初始化它的同时保持 val 私有(private)的一种简单方法是将其定义为私有(private),但使用另一个 protected 方法返回的值对其进行初始化。
然后子特征可以定义这个 protected 方法来改变初始值,但不能访问该值本身。
所以你会改变这个:

trait A {
protected val foo: Bar
}

进入:
trait A {
private val foo: Bar = initFoo
protected def initFoo: Bar
}

现在,只有特质 A可以访问 val foo .子特征可以设置 foo的初始值按定义 initFoo ,但无法访问 foo本身:
trait B extends A {
protected def initFoo: Bar = ???
}

显然, initFoo本身仍然可以通过子特征访问。
如果 initFoo,这通常不是问题。每次都创建一个新实例(换句话说,它是一个工厂),
因为我们可能只对将实例设为 A 私有(private)感兴趣。无需担心子特征能够创建 Bar 的新实例
(不管新实例是否等于 foo 根据它们的 equals 方法)。

但是,如果这是一个问题(并且在您的情况下肯定是 seed 是 fo 类型 Int,因此您要隐藏的是一个值而不仅仅是一个引用),
我们可以使用一个额外的技巧来允许子特征定义 initFoo但阻止他们(和他们的子特征)能够调用它。
让我们面对现实吧,这个技巧对于这种简单的需求来说非常糟糕,但它说明了高级访问控制的一个很好的模式。
归功于标准库作者的想法(见 http://www.scala-lang.org/api/current/index.html#scala.concurrent.CanAwait)。
trait A {
// A "permit" to call fooInit. Only this instance can instantiate InitA
abstract class InitA private[this]()
// Unique "permit"
private implicit def initA: InitA = null

private def foo: Int = fooInit
protected def fooInit( implicit init: InitA ): Int
}

trait B extends A {
protected def fooInit( implicit init: InitA ): Int = 123
}

现在,如果 B尝试调用 initFoo ,编译器会提示找不到 InitA 类型的隐式。 (唯一的此类实例是 A.initA 并且只能在 A 中访问)。

正如我所说,这有点糟糕,并且 axel22 提供的包私有(private)解决方案肯定是一个更容易的选择(尽管它不会阻止任何人在与您相同的包中定义他们的子特征,从而克服访问限制)。

关于scala - Scala trait 中的抽象私有(private)字段,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15836293/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com