Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/18.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scala中的抽象私有字段_Scala_Traits - Fatal编程技术网

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
}
现在,只有trait
A
可以访问val
foo
。子特征可以通过definint
initFoo
设置
foo
的初始值,但不能访问
foo
本身:

trait B extends A {
  protected def initFoo: Bar = ???
}
显然,
initFoo
本身仍然可以通过子特征访问。 如果每次
initFoo
都创建一个新实例(换句话说,它是一个工厂),这通常不是问题, 因为我们可能只关心将实例私有化为
A
,而不关心子特征是否能够创建
Bar
的新实例 (无论新实例是否根据其
equals
方法等于
foo

但如果这是一个问题(在您的情况下,它肯定是作为
seed
是fo type
Int
,因此您想要隐藏的是一个值,而不仅仅是一个引用), 我们可以使用另一个技巧来允许子特征定义
initFoo
,但阻止它们(及其子特征)调用它。 面对现实,对于这样一个简单的需求,这个技巧非常糟糕,但它展示了一个高级访问控制的好模式。 标准图书馆的作者将获得该想法的学分(请参阅)

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


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

拥有私有而未实现的东西有什么意义?这是一个矛盾,因为它不是继承的,也永远无法实现,因此会阻止任何带有这样一个成员的trait子类型的实例化。如果您需要子类来定义seed(覆盖其定义),那么将其设置为私有是没有意义的。也就是说,定义种子成员实现的子类将始终能够使用公共访问器显示它。我无法理解这种设计选择背后的需求。我认为这可以归结为能够让直接子特征定义种子的值,而使其他子特征(和外部代码)无法访问该值。有点像一个受保护的价值观(对待子特征就像是一个受保护的价值观,对待一切事物都是私有的)。至于意义,我认为这个想法只是完全模拟通过参数(在类中)可以完成的事情,如他的示例所示。对不起,我的意思是“有点像一个一级保护值”“现在,如果B尝试调用foo,编译器将…”,你的意思是“如果B尝试调用fooInit”?