加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

Scala特征中的抽象私有字段

发布时间:2020-12-16 18:44:56 所属栏目:安全 来源:网络整理
导读:我碰巧发现它不允许有抽象的私有字段 特征,即 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和@ pagoda_5b指出的那样,我的问题并不多
感.但幸运的是,@Régis和@ axel22已经把它变成了另一个有趣的东西
问题并提供了解决问题的模式.

解决方法

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

trait A {
  protected val foo: Bar
}

成:

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

现在,只有特征A可以访问val foo.子特征可以通过definint initFoo设置foo的初始值,但不能访问foo本身:

trait B extends A {
  protected def initFoo: Bar = ???
}

显然,initFoo本身仍然可以通过子特征访问.
如果initFoo每次都创建一个新实例(换句话说,它是一个工厂),这通常不是问题,
因为我们可能只对将实例设为私有而感兴趣,而不关心子特征是否能够创建Bar的新实例
(不论新实例是否等于foo,按照其等于方法).

但是如果它是一个问题(并且它确实在你的情况下因为种子是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给出的包私有解决方案当然是一个更容易的替代方案(虽然它不会阻止任何人在同一个包中定义他们的子特征,因此会破坏访问限制).

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读