当方法以一种看似无关的方式重载时,为什么 Scala 无法编译? [英] Why does scala fail to compile when method is overloaded in a seemingly unrelated way?

查看:45
本文介绍了当方法以一种看似无关的方式重载时,为什么 Scala 无法编译?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆