Scala 当类型已知时,为什么对重载定义的引用不明确?
我有这样一个函数:Scala 当类型已知时,为什么对重载定义的引用不明确?,scala,compiler-construction,Scala,Compiler Construction,我有这样一个函数: def ifSome[B, _](pairs:(Option[B], B => _)*) { for((paramOption, setFunc) <- pairs) for(someParam <- paramOption) setFunc(someParam) } 然后,以下行生成一个错误: ifSome(Option("hi") -> f.setB _) <console>:11: error: ambiguous r
def ifSome[B, _](pairs:(Option[B], B => _)*) {
for((paramOption, setFunc) <- pairs)
for(someParam <- paramOption) setFunc(someParam)
}
然后,以下行生成一个错误:
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 _)
但是我想理解为什么这是必要的。Scala中的类型推断只能从一个参数列表到下一个参数列表。由于您的
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)
}
并相应地将调用更改为ifSome
:
ifSome(Option("hi"))(f.setB _)
这一切都很有效。当然,现在您必须检查
opts
和funs
在运行时是否具有相同的长度。您需要尝试$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
正如我在回答中所解释的,类型推断(计算出B是字符串)可以从一个参数列表工作到下一个参数列表。这是关于参数列表的。感谢第二种解决方法,但我仍然不明白为什么有必要这么做。另外,你能解释一下你的例子中推断出了什么,我的例子中没有推断出什么吗?据我所知,我希望编译器能够从Foo中可用的类型推断出调用站点中选项的类型。更改ifSome的参数列表如何向编译器提供更多关于Foo中可用类型的信息?实际上,我想我正在接近理解。您的意思是,编译器不会检查选项[B]中的类型B是否与B=>\中的类型B匹配,因为它们位于同一个参数列表中,但如果将它们放在单独的列表中,编译器将进行检查并使用该信息从Foo中选择正确的函数。但这似乎也不对,因为如果我执行
ifSome(选项(1)->((x:String)=>x+“test”)
编译器会注意到我在B上有一个类型不匹配。如果编译器可以检查以注意到不匹配,为什么它不能选择正确的函数呢?是的,这就是我要说的。我不熟悉编译器的内部结构,所以我无法解释为什么它有这个限制,或者为什么它不能很容易地被删除。
ifSome(Option("hi"))(f.setB _)
[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 _))
}