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



在玩Scala时,我有这样的代码:

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

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

现在,我的问题是:在这种情况下,我如何访问Superclass的现场i

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

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

作为旁注,还存在以下语法,可用于方法成员(可能并不为人所知(

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

@MarioGalic回答了这个问题。我只想做一些太长而无法评论的补充。

常见的误解是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 for the impatient"中写道(第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 中我无法确认第二种情况。


现在让我们有两个类。

斯卡拉不允许

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或简称iSubclass的场private[this] val i: Int(this: Superclass).iSuperclass的场var i: Int


scala 构造函数参数默认为私有 val 吗?

Scala 构造函数参数

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

最新更新