当方法以一种看似无关的方式重载时,为什么 Scala 无法编译? [英] Why does scala fail to compile when method is overloaded in a seemingly unrelated way?
问题描述
class A {}
class B extends A {}
object Sample {
def foo(a: Set[A]) {
println("Hi Set[A]")
}
// def foo(a: String) {
// println("Hi A")
// }
}
Sample.foo(Set(new B()))
上面的代码与 scala
运行起来很愉快.但是,当我取消注释 foo(a: String)
时,代码无法编译:
The above code runs happily with scala
. However, when I uncomment foo(a: String)
, the code fails to compile:
test.scala:13: error: overloaded method value foo with alternatives:
(a: String)Unit <and>
(a: Set[this.A])Unit
cannot be applied to (scala.collection.immutable.Set[this.B])
Sample.foo(Set(new B()))
^
one error found
foo(a: String)
似乎与尝试使用 Set[B]
调用 foo
无关.这是怎么回事?
foo(a: String)
seems like it should have nothing to do with trying to call foo
with a Set[B]
. What is going on?
让我困惑的不仅仅是为什么未注释的版本不能编译,还有为什么它可以编译,当 foo(a: String)
是注释掉了.通过添加方法 foo(a: String)
我改变了什么?
The thing that confuses me isn't just why the uncommented version doesn't compile, but also why it does compile, when foo(a: String)
is commented out. What am I changing by adding the method foo(a: String)
?
Set
不变并不能解释为什么当 foo(a: String)
被注释掉时它编译成功.
Set
being invariant doesn't explain why it compiles successfully when foo(a: String)
is commented out.
推荐答案
在工作情况下,Set.apply[T]
的类型参数被推断为 A
> 因为 Set[A]
是函数参数的预期类型.
In the working case, the type param to Set.apply[T]
is inferred to be A
because Set[A]
is the expected type of the function param.
重载解析类型检查没有预期类型的参数,因此编译器不能再使用 Set[A]
来指导推断您想要的集合.
Overloading resolution typechecks arguments without an expected type, so the compiler can no longer use Set[A]
to guide inference of what set you intend.
这是 规范,尽管现在它被更多关于 SAM 的词所掩盖.
That's an important take-away from the spec, though now it is a bit buried by more words about SAMs.
否则,让 Si... 成为通过键入每个类型获得的类型列表论证如下.[关于函数的一些东西.] 所有其他参数输入了未定义的预期类型.
Otherwise, let Si... be the list of types obtained by typing each argument as follows. [Something about functions.] All other arguments are typed with an undefined expected type.
如果它知道需要 Set[A]
,那么你的集合就是这样输入的,而不是 Set[B]
.
If it knows a Set[A]
is expected, your set is typed that way, not as a Set[B]
.
您可以使用 -Ytyper-debug
观察打字决策,它会发出偶尔难以理解的输出.
You can observe typing decisions with -Ytyper-debug
, which emits output that is occasionally not inscrutable.
给定
class A ; class B extends A
object X { def f(as: Set[A]) = ??? ; def f(s: String) = ??? }
object Main extends App {
X.f(Set(new B))
}
此处,value 参数的类型为 Set[B]
,然后它尝试并未能找到到重载的 param 类型的隐式转换.
Here, the value argument is typed as Set[B]
, and then it attempts and fails to find an implicit conversion to the param types of the overload.
它还寻找将 X
对象转换为带有 f
方法的类型,该方法采用 Set[B]
.>
It also looks for a conversion of the X
object to a type with an f
method that takes Set[B]
.
| |-- X.f(Set(new B())) BYVALmode-EXPRmode (site: value <local Main> in Main)
| | |-- X.f BYVALmode-EXPRmode-FUNmode-POLYmode (silent: value <local Main> in Main)
| | | |-- X EXPRmode-POLYmode-QUALmode (silent: value <local Main> in Main)
| | | | \-> X.type
| | | \-> (s: String)Nothing <and> (as: Set[A])Nothing
| | |-- Set(new B()) BYVALmode-EXPRmode (silent: value <local Main> in Main)
| | | |-- Set BYVALmode-EXPRmode-FUNmode-POLYmode (silent: value <local Main> in Main)
| | | | |-- scala.Predef.Set.apply BYVALmode-EXPRmode-FUNmode-POLYmode (silent: value <local Main> in Main)
| | | | | [adapt] [A](elems: A*)CC[A] adapted to [A](elems: A*)CC[A]
| | | | | \-> (elems: A*)scala.collection.immutable.Set[A]
| | | | [adapt] => scala.collection.immutable.Set.type adapted to [A](elems: A*)CC[A]
| | | | \-> (elems: A*)scala.collection.immutable.Set[A]
| | | |-- new B() BYVALmode-EXPRmode-POLYmode (silent: value <local Main> in Main)
| | | | |-- new B BYVALmode-EXPRmode-FUNmode-POLYmode (silent: value <local Main> in Main)
| | | | | |-- new B EXPRmode-POLYmode-QUALmode (silent: value <local Main> in Main)
| | | | | | |-- B FUNmode-TYPEmode (silent: value <local Main> in Main)
| | | | | | | \-> B
| | | | | | \-> B
| | | | | \-> ()B
| | | | \-> B
| | | solving for (A: ?A)
| | | \-> scala.collection.immutable.Set[B]
| | [search #1] start `(s: String)Nothing <and> (as: Set[A])Nothing`, searching for adaptation to pt=scala.collection.immutable.Set[B] => String (silent: value <local Main> in Main) implicits disabled
| | 15 implicits in companion scope
| | [search #2] start `(s: String)Nothing <and> (as: Set[A])Nothing`, searching for adaptation to pt=(=> scala.collection.immutable.Set[B]) => String (silent: value <local Main> in Main) implicits disabled
| | 15 implicits in companion scope
| | [search #3] start `(s: String)Nothing <and> (as: Set[A])Nothing`, searching for adaptation to pt=scala.collection.immutable.Set[B] => Set[A] (silent: value <local Main> in Main) implicits disabled
| | 15 implicits in companion scope
| | [search #4] start `(s: String)Nothing <and> (as: Set[A])Nothing`, searching for adaptation to pt=(=> scala.collection.immutable.Set[B]) => Set[A] (silent: value <local Main> in Main) implicits disabled
| | 15 implicits in companion scope
| | second try: <error> and Set(new B())
| | |-- Set(new B()) EXPRmode (silent: value <local Main> in Main)
| | | |-- Set BYVALmode-EXPRmode-FUNmode-POLYmode (silent: value <local Main> in Main)
| | | | |-- scala.Predef.Set.apply BYVALmode-EXPRmode-FUNmode-POLYmode (silent: value <local Main> in Main)
| | | | | [adapt] [A](elems: A*)CC[A] adapted to [A](elems: A*)CC[A]
| | | | | \-> (elems: A*)scala.collection.immutable.Set[A]
| | | | [adapt] => scala.collection.immutable.Set.type adapted to [A](elems: A*)CC[A]
| | | | \-> (elems: A*)scala.collection.immutable.Set[A]
| | | solving for (A: ?A)
| | | \-> scala.collection.immutable.Set[B]
| | [search #5] start `X.type`, searching for adaptation to pt=X.type => ?{def f(x$1: ? >: scala.collection.immutable.Set[B]): ?} (silent: value <local Main> in Main) implicits disabled
| | [search #6] start `X.type`, searching for adaptation to pt=(=> X.type) => ?{def f(x$1: ? >: scala.collection.immutable.Set[B]): ?} (silent: value <local Main> in Main) implicits disabled
badset.scala:7: error: overloaded method value f with alternatives:
(s: String)Nothing <and>
(as: Set[A])Nothing
cannot be applied to (scala.collection.immutable.Set[B])
这篇关于当方法以一种看似无关的方式重载时,为什么 Scala 无法编译?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!