使用鸭子类型在 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 def
。 this 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 已经给出了这个答案。我只是将它插入到您的示例代码中。
我刚刚发现了如何使用 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 def
。 this 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 traitA
of type()Unit
; methodfoo
in traitC
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 已经给出了这个答案。我只是将它插入到您的示例代码中。