使用duck typing在Scala中创建mixins,我可以在一个没有知识的类中装饰现有的方法吗? mixin特质?

时间:2015-07-31 00:20:23

标签: scala mixins traits

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

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) 由mixin方法装饰的类?

这就是我想要这样做的原因:(1)说我有采用Tarbar实例的方法...... 并且(2)让我们说这个方法和它引用的Tarbar类是在没有的情况下开发的 我的要求是每次在Tarbar上调用origGreetingMethod之后我都需要做点什么 else(收集指标,清理......无论如何)。

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

如果我可以调整Foobar以便覆盖其中的行为,那将是非常方便的 origGreetingMethod并不要求我调用decoratedGreetingMethod来获取它 新功能。

我尝试了这篇文章中提到的抽象覆盖方法: Mixins in Scala

但我无法让它发挥作用。任何指导最感谢! 感谢

2 个答案:

答案 0 :(得分:1)

我开始玩一些代码。我想知道这是不是你的想法:

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$1@cbf6c1e

scala> y.origGreetingMethod()
hello
extra

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

答案 1 :(得分:0)

的方式是使用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。到目前为止,这么好,但那是我偶然发现的地方:

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

给出以下错误消息:

  

foo类型的特征A中覆盖方法()Unit;类型为foo的特征C中的方法()Unit无法覆盖具体成员而没有被两者覆盖的第三个成员(此规则旨在防止意外覆盖'')

我并不完全明白“[除非有]第三个被两个人覆盖的成员”,但最终它不起作用。是否是一个错误(因为abstract override不能解决这些问题并且它应该有效),abstract override的实施限制,或者真正有用的错误(因为abstract override确实是危险的我不知道。

所以,抱歉,我最终无法帮助你。我会继续提出这些后续问题:

  • 有没有办法使用特质C,还是总能得到错误?
  • 混合特性C会有什么危害?
  • 错误消息是Scala编译器的误报,还是防止危险结构所必需的?
  • 编译器消息的含义是什么?

(如果您要问这些问题,请留下一个链接,这对我来说也很有趣)