我有这样的功能:
def ifSome[B, _](pairs:(Option[B], B => _)*) {
for((paramOption, setFunc) <- pairs)
for(someParam <- paramOption) setFunc(someParam)
}
并重载了这些函数:
class Foo{
var b=""
def setB(b:String){this.b = b}
def setB(b:Int){this.b = b.toString}
}
val f = new Foo
然后以下行产生错误:
ifSome(Option("hi") -> f.setB _)
<console>:11: error: ambiguous reference to overloaded definition,
both method setB in class Foo of type (b: Int)Unit
and method setB in class Foo of type (b: String)Unit
match expected type ?
ifSome(Option("hi") -> f.setB _)
但是编译器知道我们正在寻找一个Function1 [java.lang.String,_],那么为什么Function1 [Int,_]的存在会引起任何混淆呢?我错过了什么或者这是一个编译器错误(或者它应该是一个功能请求)?
我能够通过使用类似的注释来解决这个问题
ifSome(Option("hi") -> (f.setB _:String=>Unit))
但我想了解为什么这是必要的。
答案 0 :(得分:2)
Scala中的类型推断仅适用于一个参数 list 到下一个参数。由于您的ifSome
只有一个参数列表,因此Scala不会推断任何内容。您可以按如下方式更改ifSome
:
def ifSome[B, _](opts:Option[B]*)(funs: (B => _)*) {
val pairs = opts.zip(funs)
for((paramOption, setFunc) <- pairs)
for(someParam <- paramOption) setFunc(someParam)
}
离开Foo ......
class Foo{
var b=""
def setB(b:String){this.b = b}
def setB(b:Int){this.b = b.toString}
}
val f = new Foo
并相应地将呼叫更改为ifSome
:
ifSome(Option("hi"))(f.setB _)
一切正常。当然,您必须检查opts
和funs
在运行时是否具有相同的长度。
答案 1 :(得分:2)
您需要尝试$ scalac -Ydebug -Yinfer-debug x.scala
,但首先您要最小化。
在这种情况下,你会看到在咖喱版中如何在第一个参数列表中解决B:
[infer method] solving for B in (bs: B*)(bfs: Function1[B, _]*)Nothing
based on (String)(bfs: Function1[B, _]*)Nothing (solved: B=String)
对于未经证实的版本,您会看到一些奇怪的内容
[infer view] <empty> with pt=String => Int
因为它试图消除过载的歧义,这可能会导致您进入下面的奇怪解决方案。
虚拟隐式用于解决过载的唯一目的,以便推理可以继续进行。隐式本身未使用,仍未实现???
这是一个非常奇怪的解决方案,但你知道重载是邪恶的,对吧?而且你必须用你可以使用的任何工具来对抗邪恶。
另请注意,类型注释解决方法比仅以正常方式指定类型参数更费力。
object Test extends App {
def f[B](pairs: (B, B => _)*) = ???
def f2[B](bs: B*)(bfs: (B => _)*) = ???
def g(b: String) = ???
def g(b: Int) = ???
// explicitly
f[String](Pair("hi", g _))
// solves for B in first ps
f2("hi")(g _)
// using Pair instead of arrow means less debug output
//f(Pair("hi", g _))
locally {
// unused, but selects g(String) and solves B=String
import language.implicitConversions
implicit def cnv1(v: String): Int = ???
f(Pair("hi", g _))
}
// a more heavy-handed way to fix the type
class P[A](a: A, fnc: A => _)
class PS(a: String, fnc: String => _) extends P[String](a, fnc)
def p[A](ps: P[A]*) = ???
p(new PS("hi", g _))
}