我有一个小样本代码,但它失败了,我无法解释原因
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
这也可行
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!!
这个最新的例子对我来说更清楚,当我从方法中返回它时我会从classA返回一个实例而不是类X ...
是可能的"修复"此代码并避免此行为或唯一的方法如何实现此级联方法调用使用隐式转换
答案 0 :(得分:0)
问题在于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的类型系统中,它不是类型安全的操作。正如您所说,使用隐式转换是一种做出类似建议的方法。另一个选择是让类和特性都扩展一个抽象特征,定义你想要的接口。如果不知道你真正想要完成什么,那么说什么是最好的很难。看到在Scala中返回this
的方法有点奇怪,因为这意味着您依赖于副作用。