这看起来很奇怪。以下内容可以正常编译:
def foo(s: String) = "balsh"
def foo(s: String)(s2: String) = "kahsd"
如果我隐式设置第二个参数,它仍然可以正常编译。
但是,以下情况不会:
def foo(s: String) = "bjda"
def foo(s: String)(fun: String => String) = fun(s)
^由于“对重载定义的引用不明确”而无法编译。
我最初的想法是 Scala 将函数转换为 Java 的方式导致两者的签名相同。但是,查看使用 javap 进行的编译编码(仅针对第二个函数,因为它不会同时编译这两个函数),您会发现这样的函数实际上被转换为:
public java.lang.String foo(java.lang.String, scala.Function1);
因此创建了一个单独的方法,具有不同的签名。那么为什么编译失败呢?
现在让事情变得更加混乱,下面的代码实际上编译得很好!
def foo(s: String) = "bjda"
def foo(s: String, fun: String => String) = fun(s)
如果将函数作为第一组参数的一部分,那么一切都很好!
有谁知道为什么会这样吗?
编辑:
所以我只是尝试了这个:
object main {
def write(s: String) = "sasd"
def write(s: String)(implicit s2: String => String) = s2(s)
}
我只是将第二个参数中的函数隐式化。你瞧,这编译通过了。
这是它生成的java代码:
public final class main$ extends java.lang.Object{
public static final main$ MODULE$;
public static {};
public java.lang.String write(java.lang.String);
public java.lang.String write(java.lang.String, scala.Function1);
}
这就是我对原版的期望,没有隐含的内容!
我猜编译器无法在两者之间进行选择,因为它们实际上只是返回类型不同。不可能仅根据函数的返回类型来分派参数。想想这样的签名:
def foo(s: String): String
def foo(s: String): String => String
不知道为什么如果你让它隐式地工作,我会得到同样的错误(正如我所期望的)。
def foo(s: String, fun: String => String)
另一方面,有一个可以分派到的不同参数列表。
如果有人想避免隐式黑客攻击,还有另一种方法:
def foo(s: String) = "balsh"
def foo(t: String)(s2: String) = "kahsd"
第二个函数的参数名称更改为不同的名称。然后当你想要第一个时:
foo(s = "foo")
当你想要第二个时:
foo(t = "foo")