Scala:传递没有参数的函数参数

时间:2012-10-08 03:11:09

标签: scala lazy-evaluation

Observer patterncallback是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")
}

有没有更清晰的解决方案来揭露这个?

2 个答案:

答案 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")
})