您的代码的第一个问题是一个小遗漏:您需要导入Numeric
实例的成员,以便将其+
带入范围(这实际上会num.mkNumericOps
带入范围,启用该+
方法):让我们试试这个:
def defaultParamFunc[B](z: B, y: B)(f: (B, B) => B = (v1: B,v2: B) => { v1 + v2 })(implicit num: Numeric[B]) = {
// Brings `+` into scope.
// Note that you can also just import Numeric.Implicits._ for the same effect
import num._
val ans = f(z,y)
println("ans : " + ans)
ans
}
不幸的是,这仍然无法编译。这里的问题是一个参数的默认值只能引用一个来自较早参数列表的参数。因为num
在最后一个参数列表中,所以没有办法在默认值中使用它。倒霉。
好的,所以让我们尝试智取编译器并将方法一分为二,这样我们就可以在参数num
之前有隐式参数f
:
def defaultParamFunc[B](z: B, y: B)(implicit num: Numeric[B]) = new {
// NOTE: using structural typing here is rather inefficient.
// Let's ignore that for now.
import num._
def apply(f: (B, B) => B = (v1: B, v2: B) => { v1 + v2 }) = {
val ans = f(z,y)
println("ans : " + ans)
ans
}
}
甜,它编译。我们在这里所做的是defaultParamFunc
实际返回一个(伪)函数实例。这个函数是f
作为参数的,因为我们在defaultParamFunc
body 中实例化了函数,所以引用没有问题num
。
但是,我们不要高兴得太早。如果我们尝试调用它,而不指定f
参数,编译器会不高兴:
scala> defaultParamFunc(5, 7)()
<console>:17: error: not enough arguments for method defaultParamFunc: (implicit num: Numeric[Int])((Int, Int) => Int) => Int{def apply$default$1: (Int, Int) => Int}.
Unspecified value parameter num.
defaultParamFunc(5, 7)()
哎呀。编译器认为空参数列表是针对 中的第二个(隐式)参数列表defaultParamFunc
,而不是在(伪)函数实例的参数列表中。
我们必须找到另一种不需要方法中隐式参数的defaultParamFunc
方法。磁铁图案来救援!
trait MyMagnet[B] extends ((B,B) => B)
object MyMagnet {
implicit def fromFunc[B]( f: (B, B) => B ) = new MyMagnet[B] {
def apply(z: B, y: B): B = {
val ans = f(z,y)
println("ans : " + ans)
ans
}
}
implicit def fromUnit[B](unit: Unit)(implicit num: Numeric[B]) = new MyMagnet[B]{
import num._
def apply(v1: B, v2: B): B = { v1 + v2 }
}
}
def defaultParamFunc[B](z: B, y: B)(magnet: MyMagnet[B]): B = magnet(z, y)
当然,对于这么小的结果,这有点做作。但它确实有效:
scala> defaultParamFunc(2,3)()
res15: Int = 5
scala> defaultParamFunc(2,3){(x:Int, y:Int) => x*y }
ans : 6
res16: Int = 6
请注意,尽管使用磁铁模式,我们已经失去了类型推断的好处。所以我们不能只做以下事情:
scala> defaultParamFunc(2,3)(_ * _)
<console>:18: error: missing parameter type for expanded function ((x$1, x$2) => x$1.$times(x$2))
defaultParamFunc(2,3)(_ * _)