Observer pattern或callback是Java中广泛使用的设计模式。但是,使用匿名类实现回调接口真的很痛苦,因此在Scala中为这些回调类实现引入隐式转换很常见。例如,Runnable接口的隐式转换是:
implicit def func2Runnable[F](f: => F): Runnable =
new Runnable {
def run() {
f
}
}
并且假设有一些监听器注册表:
def addMyListener(m: Runnable) {
// mock function for test
for (i <- 1 to 2) {
m.run()
}
}
然后隐式转换神奇地压缩了我的代码:
addMyListener(println("Printed twice"))
问题:
当我将多行代码块传递给addMyListener()时,只传递最后一行代码:
addMyListener {
println("This line is printed once")
println("Only this is printed twice")
}
已知的解决方法:
我在转换函数上添加了一个括号:
implicit def func2Runnable[F](f:() => F): Runnable =
new Runnable {
def run() {
f()
}
}
但是当我们使用它时它很冗长:
addMyListener(() => println("Printed twice"))
addMyListener {() =>
println("This line is printed twice")
println("This is also printed twice")
}
有没有更清晰的解决方案来揭露这个?
答案 0 :(得分:2)
好的,这里有一些值得思考的东西。我添加了第二个隐式转换,但这次必须明确触发。顺便说一下,它只与解决方法之前的部分有关。
implicit def func2Runnable2(f: => Unit) = new {
def runnable = new Runnable {
def run() {
f
}
}
}
在REPL中:
scala> addMyListener ({
| println("This line is printed once")
| println("Only this is printed twice")
| }.runnable)
This line is printed once
Only this is printed twice
This line is printed once
Only this is printed twice
所以,我的理论是第一个隐含的转换只发生在最后一行。
addMyListener ({
println("This line is printed once")
func2Runnable(println("Only this is printed twice"))
})
而不是预期的:
addMyListener(func2Runnable{
println("This line is printed once")
println("Only this is printed twice")
})
让我们测试两个假设:
scala> addMyListener ({
| println("This line is printed once")
| func2Runnable(println("Only this is printed twice"))
| })
This line is printed once
Only this is printed twice
Only this is printed twice
scala> addMyListener(func2Runnable{
| println("This line is printed once")
| println("Only this is printed twice")
| })
This line is printed once
Only this is printed twice
This line is printed once
Only this is printed twice
Yey!我想表明:)
为了更多地考虑这个问题,请注意参数Runnable本身就是名字:
def addMyListener2(m: => Runnable) {
// mock function for test
for (i <- 1 to 2) {
m.run()
}
}
scala> addMyListener2 ({
| println("This line is printed once")
| println("Only this is printed twice")
| })
This line is printed once
Only this is printed twice
This line is printed once
Only this is printed twice
猜测发生了什么:print(...)是Unit,两者都是。 {prints-inside}也是单位。所以它只是将func2Runnable的隐式转换应用到块的最后一个参数而不是块本身。
现在看到这个的正确方法是用scala -Xprint:namer
开始一个REPL会话(可能是typer而不是namer)。
答案 1 :(得分:0)
自我回答:
我发现两种类型的隐式转换可以同时应用:
implicit def lazy2Runnable[F](f: => F): Runnable =
new Runnable {
def run() {
f
}
}
implicit def func2Runnable[F](f: () => F): Runnable =
new Runnable {
def run() {
f()
}
}
虽然我们在编写多行块时应该小心,但结果代码有点改进:
addMyListener(println("Printed twice"))
addMyListener(() => {
println("This line is printed twice")
println("This is also printed twice")
})