在Scala中,我们有一个名字参数,我们可以写
def foo[T](f: => T):T = {
f // invokes f
}
// use as:
foo(println("hello"))
我现在想对一组方法做同样的事情,我想将它们用作:
def foo[T](f:Array[ => T]):T = { // does not work
f(0) // invokes f(0) // does not work
}
foo(println("hi"), println("hello")) // does not work
有什么办法可以做我想要的吗?我想出的最好的是:
def foo[T](f:() => T *):T = {
f(0)() // invokes f(0)
}
// use as:
foo(() => println("hi"), () => println("hello"))
或
def foo[T](f:Array[() => T]):T = {
f(0)() // invokes f(0)
}
// use as:
foo(Array(() => println("hi"), () => println("hello")))
编辑:正如Seth Tisue在对this answer的评论中指出的那样,提议的SIP-24并不是很有用。
这会产生问题的一个例子是效用函数trycatch
的以下代码:
type unitToT[T] = ()=>T
def trycatch[T](list:unitToT[T] *):T = list.size match {
case i if i > 1 =>
try list.head()
catch { case t:Any => trycatch(list.tail: _*) }
case 1 => list(0)()
case _ => throw new Exception("call list must be non-empty")
}
此处trycatch
采用类型()=>T
的方法列表,并连续应用每个元素,直到成功或达到结束。
现在假设我有两种方法:
def getYahooRate(currencyA:String, currencyB:String):Double = ???
和
def getGoogleRate(currencyA:String, currencyB:String):Double = ???
将currencyA
的一个单位转换为currencyB
并输出Double
。
我使用trycatch
作为:
val usdEuroRate = trycatch(() => getYahooRate("USD", "EUR"),
() => getGoogleRate("USD", "EUR"))
我更喜欢:
val usdEuroRate = trycatch(getYahooRate("USD", "EUR"),
getGoogleRate("USD", "EUR")) // does not work
在上面的示例中,我希望仅在getGoogleRate("USD", "EUR")
引发异常时才调用getYahooRate("USD", "EUR")
。这不是SIP-24的预期行为。
答案 0 :(得分:2)
从Scala 2.11.7开始,答案是否定的。但是,有SIP-24,因此在将来的某个版本中,您的f: => T*
版本可能会有效。
答案 1 :(得分:2)
Here是一个解决方案,虽然与直接按名称相比有一些限制:
import scala.util.control.NonFatal
object Main extends App {
implicit class Attempt[+A](f: => A) {
def apply(): A = f
}
def tryCatch[T](attempts: Attempt[T]*): T = attempts.toList match {
case a :: b :: rest =>
try a()
catch {
case NonFatal(e) =>
tryCatch(b :: rest: _*)
}
case a :: Nil =>
a()
case Nil => throw new Exception("call list must be non-empty")
}
def a = println("Hi")
def b: Unit = sys.error("one")
def c = println("bye")
tryCatch(a, b, c)
def d: Int = sys.error("two")
def e = { println("here"); 45 }
def f = println("not here")
val result = tryCatch(d, e, f)
println("Result is " + result)
}
限制是:
Attempt
。Nothing
类型(例如,如果b
且d
未注释),则不会插入Attempt
的转换,因为{ {1}}是每种类型的子类型,包括Nothing
。据推测,同样适用于Attempt
类型的表达式。