【问题标题】:Disambiguate constructor parameter with same name as class field of superclass消除与超类的类字段同名的构造函数参数的歧义
【发布时间】:2020-10-22 05:29:57
【问题描述】:

在使用 Scala 时,我有一个这样的代码:

class Superclass(var i : Int){}

class Subclass(i : Int) extends Superclass(0) {
   print(i)
}

我发现print(i)打印了Subclass(i : Int)的构造函数参数i

现在,我的问题是:在这种情况下,我如何访问 iSuperclass 字段?

【问题讨论】:

  • 你可以使用this.i,我想。如果你对构造函数参数有任何引用,它就会变成一个字段或类似的东西(即使你不能在外面访问它)。
  • @user 不起作用:/。 this.i 还返回构造函数参数
  • 是的,我刚刚注意到了。 scala老网站相关讨论:scala-lang.org/old/node/968

标签: scala


【解决方案1】:

Type ascription 可以向上转换 this 的类型,从而有效消除两个标识符的歧义

class Subclass(i : Int) extends Superclass(0) {
  print((this: Superclass).i)
  print(i)
}

作为旁注,还存在以下 syntax 可用于方法成员的情况(并且可能不为人所知)

super[ClassQualifier]

例如,考虑以下情况

trait A {
  def f = "A"
}

trait B extends A {
  override def f = "B"
}

class C extends A with B {
  println(super[A].f)
  println(super[B].f)
  println(f)
  
  override def f = "C"
}

new C
// A
// B
// C

【讨论】:

  • this[ClassQualifier] 是非法的。
【解决方案2】:

@MarioGalic 回答了这个问题。我将添加一些对 cme​​ts 来说太长的内容。

常见的误解是i

class MyClass(i : Int)

只是一个构造函数参数,而不是一个字段。实际上,如果我们这样做

import scala.reflect.runtime.universe._
println(reify{
  class MyClass(i : Int)
}.tree) 

我们会看到(Scala 2.13.2)

{
  class MyClass extends AnyRef {
    <paramaccessor> private[this] val i: Int = _;
    def <init>(i: Int) = {
      super.<init>();
      ()
    }
  };
  ()
}

所以没有val/var的主构造函数的参数生成private[this]字段。所以

class MyClass(i : Int)

类似于

class MyClass(private[this] val i : Int)

与 Java 不相似

public class MyClass { 
  public MyClass(int i) {
  }
}

没有字段。

我们可以检查i 是一个引用它的字段,在类主体中带有this

class MyClass(i : Int) {
  println(this.i)
}
new MyClass(1) // prints 1

字段iprivate[this],所以我们不能在类主体之外引用它(或者在与this 不同的实例主体内部)

class MyClass(i : Int) {
  //println(new MyClass(2).i) //doesn't compile
}
//new MyClass(1).i //doesn't compile

我没有在 Scala 规范中找到合适的位置,但这种行为早已为人所知。例如,在 Cay S. Horstmann 的“不耐烦的 Scala”中,它是这样写的(第 2 版,第 5.7 节):

构造参数也可以是常规方法参数,不带valvar。这些参数的处理方式取决于它们在类中的用法。

  • 如果没有valvar 的参数在至少一个方法中使用,则它成为一个字段。例如,

     class Person(name: String, age: Int) {  
       def description = name + " is " + age + " years old"
     }
    

    声明并初始化对象私有的不可变字段nameage。这样的字段等效于 private[this] val 字段(请参阅第 56 页的第 5.4 节“对象私有字段”)。

  • 否则,参数不会保存为字段。它只是一个可以在主构造函数的代码中访问的常规参数。 (严格来说,这是一个特定于实现的优化。)

其实在2.13.2我无法确认第二种情况。


现在让我们有两个类。

Scala 不允许

class Superclass {
  val i: Int = 1
}

class Subclass extends Superclass {
  //val i: Int = 2 //doesn't compile
}

除非我们添加override

class Superclass {
  val i: Int = 1
}

class Subclass extends Superclass {
  override val i: Int = 2
}

但是如果Superclass 的字段是private[this] 没有override 一切正常

class Superclass {
  private[this] val i: Int = 1
}

class Subclass extends Superclass {
  val i: Int = 2
}

实际上,如果我们尝试添加override,这将无法编译。

原因是这不是压倒一切的。其中一个字段是private[this],即在定义该字段的对象之外无法访问,因此它们只是两个不同的字段:

class Superclass {
  private[this] val i: Int = 1
}

class Subclass extends Superclass {
  val i: Int = 2

  println(this.i) // or just println(i)
// println((this: Superclass).i) //doesn't compile
}

new Subclass
//2

class Superclass {
  val i: Int = 1
}

class Subclass extends Superclass {
  private[this] val i: Int = 2

  println(this.i) // or just println(i)
  println((this: Superclass).i)
}

new Subclass
//2
//1

所以在我们的例子中

class Superclass(var i : Int)

class Subclass(i : Int) extends Superclass(0)

class Superclass extends AnyRef {
  var i: Int = _
  def this(_i: Int) = {
    super() //pseudocode
    i = _i
  }
}

class Subclass extends Superclass {
  private[this] val i: Int = _ //pseudocode
  def this(_i: Int) = {
    super(0) //pseudocode
    i = _i  //pseudocode because "i" is a val -- well, compiler can do things that we can't do in source code
  }
}

Subclassthis.i 或只是i 内指的是Subclass 的字段private[this] val i: Int(this: Superclass).i 指的是Superclass 的字段var i: Int


Do scala constructor parameters default to private val?

Scala Constructor Parameters

https://www.scala-lang.org/old/node/8384.html

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-01-31
    • 1970-01-01
    • 1970-01-01
    • 2020-10-31
    • 1970-01-01
    • 1970-01-01
    • 2021-09-23
    • 2013-10-25
    相关资源
    最近更新 更多