使用鸭子类型在 Scala 中创建混合,我可以在没有 'knowledge' 混合特性的 class 中装饰现有方法吗?

using duck typing to create mixins in Scala, can i decorate existing methods in a class that has no 'knowledge' of the mixin trait?

我刚刚发现了如何使用 duck typing 来创建 Scala 中的混合动态扩展的行为 a class 是在不知道 mixin 的情况下创建的。我能够做到这一点 创建一个 mixin,添加一个 'decorates' 现有方法的方法。这是 如下图所示。

trait Foobar {
    this: {def origGreetingMethod()} => // this is 'duck typing' right?
    def decoratedGreetingMethod() = { 
        origGreetingMethod() ; println("done greeting") 
    }
}

class Tarbar { def origGreetingMethod() = { println("hello") }}
val y = new Tarbar() with Foobar
y.decoratedGreetingMethod    // when run from REPL prints "hello\ndone greeting"

请注意,装饰方法的名称与原始方法不同。我想知道 : 有什么方法可以覆盖和扩展 ORGINAL 方法(即 origGreetingMethod) class 正在被 mixin 方法装饰?

这就是我想要这样做的原因:(1) 假设我有采用 Tarbar 实例的方法... 并且 (2) 可以说这个方法和它引用的 Tarbar class 是在没有 我的要求是每次在 Tarbar 上调用 origGreetingMethod 后我都需要做一些事情 其他(收集指标、清理……等等)。

def doSomething(tarbar: Tarbar) { 
    tarbar. origGreetingMethod
    println("doing something useful...")
}

如果我可以调整 Foobar 使其覆盖 origGreetingMethod 并且不需要我调用 decoratedGreetingMethod 来获取它 新功能。

我尝试了这个 post 中提到的抽象覆盖方法: Mixins in Scala

但我无法让它工作。非常感谢任何指导! 谢谢

这个的方式是使用abstract override defthis page 有一个很好的例子,这里是一个简单的例子:

trait Trait {
  def foo(): Unit
}

trait A extends Trait {
  def foo(): Unit = println("A")
}

trait B extends Trait {
  abstract override def foo(): Unit = { println("B"); super.foo() }
}

def main(args: Array[String]): Unit = {
  (new Object with A).foo() //output: A
  (new Object with A with B).foo() // output: B A
  //those won't compile
  //(new Object with B).foo()
  //(new Object with B with A).foo()
}

现在开始鸭子打字:我写了一个这样的特征:

trait C {
  self: { def foo(): Unit } =>
  abstract override def foo(): Unit = { println("B"); self.foo() }
}

请注意,super.foo() 不起作用。 Scala 承认 abstract override 是合法的(如果没有 self 类型就不会),但是对委托的调用是通过 self。到目前为止,一切都很好,但这就是我绊倒的地方:

(new Object with A with C).foo()

给出以下错误信息:

overriding method foo in trait A of type ()Unit; method foo in trait C of type ()Unit cannot override a concrete member without a third member that's overridden by both (this rule is designed to prevent accidental overrides'')

我不太明白“[除非有]第三个成员被两者覆盖”是什么意思,但最终它不起作用。无论是错误(因为 abstract override 不会有这些问题,它应该可以工作)、abstract override 实现的限制,还是真正有用的错误(因为 abstract override 确实很危险在这里),我不知道。

所以,很抱歉我最终没能帮到你。我会继续回答这些后续问题:

  • 有什么方法可以使用 trait C,或者你会一直遇到那个错误吗?
  • 混合特征 C 会带来什么危害?
  • 错误消息是 Scala 编译器的误报,还是防止危险构造所必需的?
  • 编译器消息的确切含义是什么?

(如果你要问这些问题,请留下一个link,我也会感兴趣)

我开始研究一些代码。我想知道这是否是您想要的:

scala> class Tarbar { def origGreetingMethod() = println("hello") }
defined class Tarbar

scala> trait Foobar extends Tarbar {
     | abstract override def origGreetingMethod() = {
     | super.origGreetingMethod()
     | println("extra") }}
defined trait Foobar

scala> val y = new Tarbar() with Foobar
y: Tarbar with Foobar = $anon@cbf6c1e

scala> y.origGreetingMethod()
hello
extra

我认为@SillyFreak 已经给出了这个答案。我只是将它插入到您的示例代码中。