看这个例子:
def hello(a:String, b:String) = println(a + ":" + b)
val m1 = hello("aaa", _ )
m1("bbb")
它无法编译,我需要将类型添加到部分方法中:
val m1 = hello("aaa", _: String)
为什么scala不知道方法的第二个参数hello
是String
?
看这个例子:
def hello(a:String, b:String) = println(a + ":" + b)
val m1 = hello("aaa", _ )
m1("bbb")
它无法编译,我需要将类型添加到部分方法中:
val m1 = hello("aaa", _: String)
为什么scala不知道方法的第二个参数hello
是String
?
Scala 的类型推断是基于流的。方法和函数需要显式参数类型,用于推断其他类型。参数类型不能从方法或函数体中推断出来。然而,有时,参数类型是从外部上下文中获知的,因此不必标记。两个例子,
val f: String => Unit = hello("aaa", _)
val s = Seq(1,2).map(_+1) // Seq[Int].map expects a function of Int argument type
下面是 Martin Odersky 引用的关于 Scala 类型推断与 ML 和 Haskell 相比的局限性的引述。挑战包括 Scala 的重载、记录选择和子类型化,以及保持简单的需要,
Scala 没有 Hindley/Milner 类型推断的原因是它很难与重载(即席变体,不是类型类)、记录选择和子类型等特性结合起来。我并不是说不可能——存在许多包含这些功能的扩展;事实上,我自己也对其中一些人感到内疚。我只是说在实践中很难让它很好地工作,需要有小的类型表达式和好的错误消息。这也不是一个封闭的案例——许多研究人员正在努力突破这里的界限(例如,看看 Remy 的 MLF)。但现在它是更好的类型推理与更好地支持这些特性的权衡。您可以通过两种方式进行权衡。
资料来源:Universal Type Inference is a Bad Thing帖子下的评论。
简单来说,Scala 使用参数类型来寻找合适的方法,而不是方法类型来推断参数的类型。
要执行您想要的操作,它必须hello
使用两个参数搜索所有可能的调用,其中第一个参数String
- 可能包括隐式转换 - 然后,如果找到一个最具体的选项,则使用它来推断第二个参数的类型。除了它已经做的所有事情之外,它还必须这样做,从而进一步减慢已经相当慢的编译速度。并非不可能,但它不会那样做。
这可能是因为这个定义存在潜在的歧义,hello
可能会被重载。
// inside some class context
def hello(a:String, b:String) = println(a + ":" + b)
def hello(a:String, b:Int) = println(a + ":" + b.toString)
val m1 = hello("aaa", _ ) // which one to choose?
考虑到不仅仅是你能做到val m1 = hello("aaa", _)
。可能有您班级的用户正在执行val my_hello = (new C).hello("aaa", _)
. 然后,您通过向原始字符串 hello 方法添加重载来破坏源代码兼容性,因为突然之间不再清楚应该做什么了。
我不确定这是唯一的原因,但肯定可以将其视为一种安全措施。