首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >当类型已知时,为什么对重载定义的引用是不明确的?

当类型已知时,为什么对重载定义的引用是不明确的?
EN

Stack Overflow用户
提问于 2012-09-29 06:09:48
回答 2查看 1.4K关注 0票数 4

我有一个这样的函数:

代码语言:javascript
运行
复制
def ifSome[B, _](pairs:(Option[B], B => _)*) {
  for((paramOption, setFunc) <- pairs)
    for(someParam <- paramOption) setFunc(someParam)
}

以及像这样的重载函数:

代码语言:javascript
运行
复制
class Foo{ 
  var b=""
  def setB(b:String){this.b = b}
  def setB(b:Int){this.b = b.toString}
}

val f = new Foo

然后,下面的行将生成一个错误:

代码语言:javascript
运行
复制
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 _)

但是编译器知道我们要找的是一个Function1java.lang.String,_,那么为什么Function1Int的存在会引起混淆呢?我是不是遗漏了什么,或者这是一个编译器错误(或者它可能应该是一个特性请求)?

我可以通过使用如下所示的类型注释来解决此问题

代码语言:javascript
运行
复制
ifSome(Option("hi") -> (f.setB _:String=>Unit))

但我想知道为什么这是必要的。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2012-09-29 13:13:24

你会想要尝试$ scalac -Ydebug -Yinfer-debug x.scala,但首先你会想要最小化。

在本例中,您将看到在curried版本中,B是如何在第一个参数列表中求解的:

代码语言:javascript
运行
复制
[infer method] solving for B in (bs: B*)(bfs: Function1[B, _]*)Nothing 
based on (String)(bfs: Function1[B, _]*)Nothing (solved: B=String)

对于未加糖的版本,你会看到一些奇怪的地方

代码语言:javascript
运行
复制
[infer view] <empty> with pt=String => Int

因为它试图消除重载的歧义,这可能会导致下面奇怪的解决方案。

虚拟隐式的唯一目的是解决过载,以便推理可以继续进行。隐式本身未使用,并且保持未实现的???

这是一个非常奇怪的解决方案,但是你知道重载是邪恶的,对吧?你必须使用任何你可以使用的工具来对抗邪恶。

另请注意,您的类型注释变通方法比仅以正常方式指定类型参数更费力。

代码语言:javascript
运行
复制
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 _))
}
票数 2
EN

Stack Overflow用户

发布于 2012-09-29 06:34:32

Scala中的类型推断只适用于从一个参数列表到下一个参数列表。因为您的ifSome只有一个参数列表,所以Scala不会推断任何东西。您可以按如下方式更改ifSome

代码语言:javascript
运行
复制
def ifSome[B, _](opts:Option[B]*)(funs: (B => _)*) {
  val pairs = opts.zip(funs)
  for((paramOption, setFunc) <- pairs)
    for(someParam <- paramOption) setFunc(someParam)
}

让Foo保持原样...

代码语言:javascript
运行
复制
class Foo{ 
  var b=""
  def setB(b:String){this.b = b}
  def setB(b:Int){this.b = b.toString}
}

val f = new Foo

并相应地更改对ifSome的调用:

代码语言:javascript
运行
复制
ifSome(Option("hi"))(f.setB _)

这一切都很好用。当然,现在您必须检查optsfuns在运行时是否具有相同的长度。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/12648019

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档