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

时间:2014-08-08 00:51:50

标签: 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

这也可行

           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 ...

是可能的"修复"此代码并避免此行为或唯一的方法如何实现此级联方法调用使用隐式转换

1 个答案:

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