Scala 消除与超类的类字段同名的构造函数参数的歧义

Scala 消除与超类的类字段同名的构造函数参数的歧义,scala,Scala,在使用Scala时,我的代码如下: class Superclass(var i : Int){} class Subclass(i : Int) extends Superclass(0) { print(i) } 我发现print(I)打印子类(I:Int) 现在,我的问题是:在这种情况下,如何访问超类的I字段?可以向上转换this的类型,从而有效地消除两个标识符的歧义 class Subclass(i : Int) extends Superclass(0) { print(

在使用Scala时,我的代码如下:

class Superclass(var i : Int){}

class Subclass(i : Int) extends Superclass(0) {
   print(i)
}
我发现
print(I)
打印
子类(I:Int)

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

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

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

作为旁注,在方法成员的情况下也可以使用以下内容(可能还不为人所知)

例如,考虑下面的

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

@MarioGalic回答了这个问题。我只想添加一些太长的评论

常见的误解是,
i
in

class MyClass(i : Int)
只是一个构造函数参数,而不是字段。事实上,如果我们这样做

import scala.reflect.runtime.universe._
println(reify{
  class MyClass(i : Int)
}.tree) 
我们拭目以待(Scala 2.13.2)

类似于

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
字段
i
private[this]
,因此我们不能在类主体之外引用它(或者在与
this
不同的实例主体内部引用它)

我在Scala规范中找不到合适的位置,但这种行为在很长一段时间内是众所周知的。例如,在Cay S.Horstmann的“不耐烦者的Scala”中,它写道(第2版,第5.7节):

构造参数也可以是常规方法参数,没有
val
var
。如何处理这些参数取决于它们在类中的用法

  • 如果在至少一个方法中使用了不带
    val
    var
    的参数,则该参数将成为字段。比如说,

     class Person(name: String, age: Int) {  
       def description = name + " is " + age + " years old"
     }
    
    声明和初始化对象私有的不可变字段
    name
    age
    。此类字段相当于
    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
}
除非我们添加
覆盖

class Superclass {
  val i: Int = 1
}

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

class Subclass extends Superclass {
  val i: Int = 2
}
但是如果
超类
的字段是
私有的[this]
如果没有
覆盖

class Superclass {
  val i: Int = 1
}

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

class Subclass extends Superclass {
  val i: Int = 2
}
实际上,如果我们试图添加
覆盖
,这将无法编译

原因是这不是最重要的。其中一个字段是
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(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
  }
}
子类
或只是
i
中,i
指的是
子类
的字段
private[this]val i:Int和
(this:Superclass)。i
指的是
超类
的字段
var i:Int



你可以用
这个。我想我可以用
。如果您有任何对构造函数参数的引用,则会将其转换为字段或类似的内容(即使您无法在外部访问它)。@user不工作:/。我还返回了构造函数参数是的,我注意到了。旧scala网站上的相关讨论:
此[ClassQualifier]
是非法的。
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
  }
}