【问题标题】:Scala: Accessing protected field of companion object's traitScala:访问伴生对象特征的受保护字段
【发布时间】:2012-11-22 16:59:09
【问题描述】:

我在 Scala 中有一个 Trait、一个 Companion Object 和一个类:

trait A {
    protected var foo = "Foo"
}

object B extends A {
}

class B {
     println(B.foo)
}

为什么我无法访问 foo?我认为 foo 会成为对象“B”的一个字段。有没有办法做到这一点?

【问题讨论】:

  • 我认为情况不同。我理解为什么一个实例不能访问另一个实例上的受保护字段。我对多米尼克的评论中详细说明了我不明白的内容。

标签: scala


【解决方案1】:

Scala 默认使用公共字段。它也有私有和受保护的。私有修饰符的工作方式与 Java 相同,但受保护的工作方式截然不同。

第一个区别是protected可以有两种形式:protectedprotected[bar]。其中bar 可以是类、包或对象。

来自Scala language spec

受保护的标识符 x 可以用作选择 r 中的成员名称 .x 仅在以下情况之一适用时:

– 访问在定义成员的模板内,或者,如果 限定 C 在包 C、类 C 或其 配套模块,或

--r是this和super的保留字之一,或者

– r 的类型符合包含的类的类型实例 访问权限。

换句话说,非参数化的受保护字段仅对来自同一个包的子类不可见

【讨论】:

  • 但是对象 A 的字段 foo 本质上不是变成对象 B 的字段吗,因为 A 正在混入 B 中?类可以访问其伴生对象的受保护字段吗?
  • 此报价适用于合格的访问案例,protected[C]。朴素的情况是前一段。我同意 OP 的观点,即伴随模块与伴随类不同并不明显;出于这个原因,正在讨论改变命名法。
【解决方案2】:

规范说您可以从以下位置访问受保护的成员:

任何这些类的伴随模块[以定义模板为基础]。

也就是说,不是来自以定义模板为基础的对象的伴随类。棘手。

由于“模块”命名法,这并不明显,其中模块仅表示对象。偶尔有人谈论改变这一点。尽管类和模块可以是伙伴关系,但关系不是对称的;考虑隐式搜索。

trait A {
  protected var foo = "Foo"
  protected def bar = "Bar"
}

object B extends A {
  //override protected var foo = super.foo // no
  override protected def bar = super.bar
}

class B {
  //println(B.foo) // no
  println(B.bar) // ok
}


class C extends A

object C {
  println(new C().foo)  // ok
}

【讨论】:

  • 通过阅读规范的那部分,似乎如果 foo 在对象 B 中定义,则 B 类应该无法访问它,但它可以。你同意吗?
  • 并非如此:class-private 是明确的伴随模块或伴随类。很难想象受保护的删除访问。您可能是对的,它应该说“定义模板和同伴”。对象上的受保护成员是病态的,除了您显示的情况;重新定义对象上的成员是增加可见性的一种方式(对于伴生类);这是不将 trait 成员定义为 var(使用 defs)的另一个原因。
  • 所以基本上,如果我想让它工作,我需要将 foo 定义为 A 中的 def,并覆盖对象 B 中的 foo。对象 B 中的 Foo 会调用 A 中的 Foo?
  • 如图所示。根据 SO sn-ps 应该始终显示最佳实践的理论,我几乎将其更改为 def,模数该问题可能表明的任何误解。这个问题绝对应该出现在某人的面试问题列表中。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-21
相关资源
最近更新 更多