【问题标题】:How to use scala trait with `self` reference?如何使用带有`self`引用的scala trait?
【发布时间】:2012-05-04 16:36:45
【问题描述】:

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

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

我想知道为什么会发生错误以及如何以这种方式使用 trait?

【问题讨论】:

  • 我想知道为什么会发生错误以及如何以这种方式使用 trait?
  • 我很高兴你遇到了这个错误,因为它我学到了更多关于特征的知识。 :) 尤其有趣的是,您可以通过这种方式指定 trait 可以应用于哪些类型的事物的限制。
  • 因为这是我第一次使用这种类型的语法,我想知道trait SomeTrait { this: SomeType => .... }trait SomeTrait extends SomeType { ... } 之间有什么区别?

标签: scala


【解决方案1】:

发生错误是因为您将this 引用(您已命名为self)的类型限制为Self 类型。当您说new Self with SelfAware 时,这没关系,因为该对象的类型为Self,就像您问的那样。但是当你说new X with SelfAware 时,没有证据表明XSelf 的子类型。

X with SelfAware 类型的新对象中,其self 成员的类型是什么?好吧,它不是Self 类型,而是X 类型。但是你已经定义了特征SelfAware,所以self必须是Self类型,所以你会得到一个类型错误。

【讨论】:

    【解决方案2】:

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

    自我类型

    Ordered 可以混入任何类;它不依赖于它所混入的类的任何方法或字段。有时,一个 trait 能够使用它所混入的类的字段或方法很有用,这可以通过为 trait 指定一个自身类型来完成。可以为类或特征指定自我类型,如下所示:

    trait SpellChecker { self =>
      ...
    }
    

    self 在这个 trait 的上下文中会引用 this。别名 this 对于嵌套类或特征很有用,否则很难访问特定的 this。可以扩展语法以指定 this 的下限,完成此操作后,trait 或类可以使用此下限类的特性,因此它可以扩展或修改其行为。

    trait SpellChecker { self: RandomAccessSeq[char] =>
      ...
    }
    

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

    【讨论】:

    • 如果我错了,请纠正我,但这是否意味着 SpellChecker 特征不能与 RandomAccessSeq 或其子之一混合?这不是在某种程度上违反了 Liskov 原则吗?
    • @FrancisToth 我认为你是对的。这有效地使SpellChecker 仅适用于根为RandomAccessSeq[char] 的层次结构的子树。更糟糕的是,当您实际使用语法SomeType extends SpellChecker 时,没有明确的迹象表明SpellChecker 依赖于其self 类型的这种特化。即使SomeType 处于允许使用SpellChecker 的正确层次结构中,这对于刚通过混入SpellChecker 来专门从事自己的课程的人来说可能仍然非常神秘。
    【解决方案3】:

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

    trait SelfAware { self =>
      val me = self
    }
    
    class X
    val x = new X with SelfAware
    println(s.me)
    

    【讨论】:

    • 所以,给定val s = new Self with SelfAware;执行 s.self 编译失败,因为 s 不是 Self,而是 Self with SelfAware?
    • @KevinMeredith:不,它无法编译,因为self 不是Self 的字段,也不是SelfAware 的字段。在上面的示例中,我绑定了val me = self,这使得me 字段可用于任何具有SelfAware 特征的对象。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多