Scala 消除与超类的类字段同名的构造函数参数的歧义
在使用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(
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
}
}