Access private member in self typed trait - withou

2019-09-12 17:34发布

问题:

What might be the straightforward way to make a class's private member accessible in a self typed trait bearing that class's type?

It seems that protected does the job, but AFAIK that allows access also for subclasses, which is kind of too wide an access scope bundling to me, unless, traits with self types and subclasses are more closely related than I imagine. Can you shed some light on this?

Code fiddle:

trait CakeLayer {
  self: A =>
    println(a)
}

class A {
  protected val a: Int = 3
}

To me, the semantics of a self-typed trait are very different from those of a subclass, when I use it for the cake pattern: I'd not like any subclass to have access, but only the specific self typed trait.

回答1:

I can think of a somewhat convoluted way of enforcing this - it might inspire you (or someone else) to a more workable solution:

trait CakeLayer {
  self: A =>

  def funcToRun(a: Int) = println(a)

  runFuncOnA

}

class A {

  implicit val me: this.type = this

  private val a: Int = 3

  protected def runFuncOnA(implicit cl: CakeLayer) = cl.funcToRun(a)
}

This enforces that any subclass of A that doesn't extend CakeLayer trying to call runFuncOnA won't compile:

scala> val aa = new A // Doesn't call 'runFuncOnA' - OK
aa: A = A@6a997956

scala> val aa = new A { runFuncOnA } // Doesn't extend CakeLayer - bad!
<console>:28: error: could not find implicit value for parameter cl: CakeLayer
       val aa = new A { runFuncOnA }
                        ^

scala> val aWithCL = new A with CakeLayer // Extends CakeLayer, so calling 'runFuncOnA' is OK here:
3
aWithCL: A with CakeLayer = $anon$1@59bf1b79

Basically, the trait calls on the parent class to in-turn call back a particular method defined on the trait, passing the private value.



标签: scala