Scala中的抽象私有字段
我碰巧发现它不允许在中有抽象的私有字段 一个特点,就是,Scala中的抽象私有字段,scala,traits,Scala,Traits,我碰巧发现它不允许在中有抽象的私有字段 一个特点,就是, trait A1 { //private val a: Int // Not allowed protected val b: Int // OK } abstract class A2 (private val i: Int) // OK 如果是私有字段,那么对抽象类执行这样的操作似乎没有问题 是构造函数参数,也就是 trait A1 { //private val a: In
trait A1 {
//private val a: Int // Not allowed
protected val b: Int // OK
}
abstract class A2 (private val i: Int) // OK
如果是私有字段,那么对抽象类执行这样的操作似乎没有问题
是构造函数参数,也就是
trait A1 {
//private val a: Int // Not allowed
protected val b: Int // OK
}
abstract class A2 (private val i: Int) // OK
所以我猜一个特征没有构造函数参数,所以没有
初始化它们的方法,因此不允许抽象私有字段
如果它们是“受保护的”,则子类可以使用预初始化来初始化它们
领域。这种方法允许子类查看这些字段
如果我只是想初始化它们然后隐藏它们呢,
如下面的例子所示
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和@Pagota_5b所指出的,我的问题没有多大意义 感觉但幸运的是,@Régis和@axel22将它变成了另一个有趣的东西
问题,并提供了解决该问题的模式 您最好将这些包声明为私有-
private[package\u name]
。
这将允许您在执行实现的同一个包中扩展和定义trait,但是不允许客户端从其他包中使用它。在允许子特征初始化val的同时保持val私有的一种简单方法是将其定义为私有,但使用另一个受保护的方法返回的值对其进行初始化。 然后子特征可以定义此受保护的方法,以便更改初始值,但不能访问值本身。 所以你要改变这一点:
trait A {
protected val foo: Bar
}
进入:
trait A {
private val foo: Bar = initFoo
protected def initFoo: Bar
}
现在,只有traitA
可以访问valfoo
。子特征可以通过definintinitFoo
设置foo
的初始值,但不能访问foo
本身:
trait B extends A {
protected def initFoo: Bar = ???
}
显然,initFoo
本身仍然可以通过子特征访问。
如果每次initFoo
都创建一个新实例(换句话说,它是一个工厂),这通常不是问题,
因为我们可能只关心将实例私有化为A
,而不关心子特征是否能够创建Bar
的新实例
(无论新实例是否根据其equals
方法等于foo
)
但如果这是一个问题(在您的情况下,它肯定是作为seed
是fo typeInt
,因此您想要隐藏的是一个值,而不仅仅是一个引用),
我们可以使用另一个技巧来允许子特征定义initFoo
,但阻止它们(及其子特征)调用它。
面对现实,对于这样一个简单的需求,这个技巧非常糟糕,但它展示了一个高级访问控制的好模式。
标准图书馆的作者将获得该想法的学分(请参阅)
现在,如果B
尝试调用initFoo
,编译器将抱怨它找不到类型为InitA
的隐式实例(唯一的此类实例是A.InitA
,并且只能在A
中访问)
正如我所说的,这有点可怕,axel22提供的包私有解决方案当然是一个更简单的选择(尽管它不会阻止任何人在与您相同的包中定义他们的子特征,从而克服访问限制)。拥有私有而未实现的东西有什么意义?这是一个矛盾,因为它不是继承的,也永远无法实现,因此会阻止任何带有这样一个成员的trait子类型的实例化。如果您需要子类来定义seed(覆盖其定义),那么将其设置为私有是没有意义的。也就是说,定义种子成员实现的子类将始终能够使用公共访问器显示它。我无法理解这种设计选择背后的需求。我认为这可以归结为能够让直接子特征定义种子的值,而使其他子特征(和外部代码)无法访问该值。有点像一个受保护的价值观(对待子特征就像是一个受保护的价值观,对待一切事物都是私有的)。至于意义,我认为这个想法只是完全模拟通过参数(在类中)可以完成的事情,如他的示例所示。对不起,我的意思是“有点像一个一级保护值”“现在,如果B尝试调用foo,编译器将…”,你的意思是“如果B尝试调用fooInit”?