我有一个小的示例代码,但是它失败了,我不能解释原因
class ClassA(val name : String){
def hello ={
println ("hi "+name)
this
}
def Ok = {
println ("ok ")
this
}
}
trait TraitA {
self : ClassA =>
def sayHelloAgain ={
println ("hi again"+name)
this
}
}
完全可以
val x = new ClassA("Mike") with TraitA
x.hello.Ok
this works too
val x = new ClassA("Mike") with TraitA
x.sayHelloAgain
但这不是
val x = new ClassA("Mike") with TraitA
x.hello.Ok.sayHelloAgain
尝试其他方法,这也不起作用
class X extends ClassA("Mike") with TraitA
val x = new x
x.Ok.sayHelloAgain //not works
x.sayHelloAgain //works!!
这个最新的例子对我来说更清楚,当我从方法Ok返回这个时,我从类a返回一个实例,而不是类X…
可以"修复"这段代码并避免这种行为,或者完成这个级联方法调用的唯一方法是使用隐式转换
问题是您在ClassA
中的方法返回的类型是本地确定的,独立于TraitA
,并且在该上下文中唯一有意义的类型是ClassA
。运行$ scalac -print test.scala
显示:
[[syntax trees at end of cleanup]] // test.scala
package <empty> {
class ClassA extends Object {
<paramaccessor> private[this] val name: String = _;
<stable> <accessor> <paramaccessor> def name(): String = ClassA.this.name;
def hello(): ClassA = {
scala.this.Predef.println("hi ".+(ClassA.this.name()));
this
};
def Ok(): ClassA = {
scala.this.Predef.println("ok ");
this
};
def <init>(name: String): ClassA = {
ClassA.this.name = name;
ClassA.super.<init>();
()
}
};
abstract trait TraitA extends Object { self: ClassA =>
def sayHelloAgain(): ClassA
};
abstract trait TraitA$class extends { self: ClassA =>
def sayHelloAgain($this: ClassA): ClassA = {
scala.this.Predef.println("hi again".+($this.name()));
$this
};
def /*TraitA$class*/$init$($this: ClassA): Unit = {
()
}
}
}
ClassA
没有sayHellowAgain
方法,这解释了您所看到的行为。在Scala的类型系统中,它不是一个类型安全的操作。正如您所说,使用隐式转换是实现您所建议的事情的一种方法。另一种选择是让类和trait都扩展一个抽象trait来定义你想要的接口。在不知道自己真正想要实现的目标的情况下,很难说什么是最好的。在Scala中看到返回this
的方法有点奇怪,因为这意味着您依赖于副作用。