我有 this class在斯卡拉:
object Util {
class Tapper[A](tapMe: A) {
def tap(f: A => Unit): A = {
f(tapMe)
tapMe
}
def tap(fs: (A => Unit)*): A = {
fs.foreach(_(tapMe))
tapMe
}
}
implicit def tapper[A](toTap: A): Tapper[A] = new Tapper(toTap)
}
现在,
"aaa".tap(_.trim)
不编译,给出错误
error: missing parameter type for expanded function ((x$1) => x$1.trim)
为什么类型不推断为
String
?从错误看来,隐式转换确实触发了(否则错误将沿着“tap
不是类 String
的成员”)。似乎转换必须是 Tapper[String]
,这意味着参数的类型是 String => Unit
(或 (String => Unit)*
)。有趣的是,如果我注释掉
tap
中的任何一个定义,然后它确实编译。
最佳答案
6.26.3 Overloading Resolution
One first determines the set of functions that is potentially applicable based on the shape of the arguments
...
If there is precisely one alternative in B, that alternative is chosen.
Otherwise, let S1, . . . , Sm be the vector of types obtained by typing each argument with an undefined expected type.
tap
的两个重载是潜在适用的(基于参数的“形状”,这说明了 arity 和类型构造函数 FunctionN)。因此,打字机继续进行:
val x = _.trim
并失败。
更智能的算法可以采用每个备选方案的相应参数类型的最小上限,并将其用作预期类型。但这种复杂性并不值得,IMO。重载有许多极端情况,这只是另一种情况。
但是在这种情况下,如果您确实需要接受单个参数的重载,则可以使用一个技巧:
object Util {
class Tapper[A](tapMe: A) {
def tap(f: A => Unit): A = {
f(tapMe)
tapMe
}
def tap(f0: A => Unit, f1: A => Unit, fs: (A => Unit)*): A = {
(Seq(f0, f1) ++ fs).foreach(_(tapMe))
tapMe
}
}
implicit def tapper[A](toTap: A): Tapper[A] = new Tapper(toTap)
"".tap(_.toString)
"".tap(_.toString, _.toString)
"".tap(_.toString, _.toString, _.toString)
}
关于scala - 为什么 Scala 类型推断在这里失败?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3315752/