如何使用scala trait与`self`引用?

Eva*_* Y. 29 scala

我看到一些代码写特征如下:

trait SelfAware { self: Self =>
 ....
}

class Self
val s = new Self with SelfAware // this is ok
println(s.self) // error happened

class X
new X with SelfAware // error happened here
Run Code Online (Sandbox Code Playgroud)

我想知道错误发生的原因以及如何以这种方式使用特征?

Apo*_*isp 22

发生错误是因为您已将this引用的类型(您已命名self)约束为类型Self.当你说new Self with SelfAware,这没关系,因为那个对象的类型Self就像你问的那样.但是当你说new X with SelfAware,没有任何证据表明它X是一种亚型Self.

在你的新类型对象中X with SelfAware,它的self成员类型是什么?嗯,它不是类型Self,而是类型X.但是您已经定义了特征,SelfAware因此self必须是类型Self,因此您会收到类型错误.


Eva*_* Y. 21

我也在这里找到答案:http://markthomas.info/blog/?p = 92

自我类型

有序可以混合到任何类; 它不依赖于它所混合的类的任何方法或字段.有时候,一个特性能够使用它所混合的类的字段或方法是有用的,这可以通过为特征指定一个自我类型来完成.可以为类或特征指定自我类型,如下所示:

trait SpellChecker { self =>
  ...
}
Run Code Online (Sandbox Code Playgroud)

在这个特征的背景下自我将参考这个.别名这对嵌套类或特征非常有用,否则很难访问特定的类.语法可以扩展为指定下限,当完成此操作时,trait或类可以使用此下限类的功能,因此它可以扩展或修改其行为.

trait SpellChecker { self: RandomAccessSeq[char] =>
  ...
}
Run Code Online (Sandbox Code Playgroud)

编译器将检查包含SpellChecker的层次结构中的任何类是否是或扩展RandomAccessSeq [char],因此SpellChecker现在可以使用RandomAccessSeq [char]的字段或方法

  • 如果我错了,请纠正我,但这是否意味着SpellChecker特性不能与RandomAccessSeq或其中一个孩子混在一起?这不是以某种方式违反Liskov原则吗? (2认同)

Dan*_*ton 12

要回答你问题的另一半(为什么会println(s.self)产生错误?),那是因为self它不是一个字段SelfAware.但是,它可用于定义此类字段:

trait SelfAware { self =>
  val me = self
}

class X
val x = new X with SelfAware
println(s.me)
Run Code Online (Sandbox Code Playgroud)