结合scala混合、自我类型和级联方法失败.有可能避免吗?



我有一个小的示例代码,但是它失败了,我不能解释原因

    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的方法有点奇怪,因为这意味着您依赖于副作用。

最新更新