【问题标题】:Overloaded function causes "missing parameter type for expanded function" error重载函数导致“缺少扩展函数的参数类型”错误
【发布时间】:2015-04-08 20:21:56
【问题描述】:

我有以下:

class FooList[T] (data: List[T]) {
  def foo (f: (T, T) => T, n: Int) = data.reduce(f)
  def foo (f: (T, T) => T, s: String) = data.reduce(f)
}

class BarList[T] (data: List[T]) {
  def bar(f: (T, T) => T, n: Int) = data.reduce(f)
}

BarList 工作正常,FooList 失败:

scala> new FooList(List(1, 2, 3)).foo(_+_, 3)
<console>:9: error: missing parameter type for expanded function ((x$1, x$2) => x$1.$plus(x$2))
          new FooList(List(1, 2, 3)).foo(_+_, 3)

scala> new FooList(List(1, 2, 3)).foo(_+_, "3")
<console>:9: error: missing parameter type for expanded function ((x$1, x$2) => x$1.$plus(x$2))
          new FooList(List(1, 2, 3)).foo(_+_, "3")
                                         ^
scala> new BarList(List(1, 2, 3)).bar(_+_, 3)
res2: Int = 6

为什么FooList.foo 不起作用?

有什么方法可以让两个 FooList 调用同时工作?

【问题讨论】:

  • 有点奇怪,因为 T 已经在构造函数中确定了。也许重载会混淆类型推断器。

标签: scala generics type-inference overloading


【解决方案1】:

似乎类型推断只有在选择了合适的重载方法后才确定_ + _的类型,所以它在静态调度之前明确要求它;但是有解决方法:

class FooList[T] (data: List[T]) {
  def foo (n: Int)(f: (T, T) => T) = data.reduce(f)
  def foo (s: String)(f: (T, T) => T) = data.reduce(f)
}

scala> new FooList(List(1, 2, 3)).foo(3)(_ + _)
res13: Int = 6

scala> new FooList(List(1, 2, 3)).foo("3")(_ + _)
res14: Int = 6

如果你不想为客户端改变API,你可以合并两个重载的方法(第二个参数变成union type然后):

class FooList[T] (data: List[T]) {
   def foo[A] (f: (T, T) => T, NorS: A)(implicit ev: (Int with String) <:< A) = NorS match {
      case n: Int => data.reduce(f)
      case s: String => data.reduce(f)
   }
}

scala> new FooList(List(1, 2, 3)).foo(_ + _, "3")
res21: Int = 6

scala> new FooList(List(1, 2, 3)).foo(_ + _, 3)
res22: Int = 6

scala> new FooList(List(1, 2, 3)).foo(_ + _, 3.0)
<console>:15: error: Cannot prove that Int with String <:< Double.
              new FooList(List(1, 2, 3)).foo(_ + _, 3.0)
                                            ^

所以调度在这里转移到运行时,但实际界面保持不变。

【讨论】:

  • 遗憾的是,如果我可以更改这两个方法签名,我就可以更改它们的名称。该代码曾经有foo(f: (T, T) =&gt; T, a: A)foo(b: B, f: (T, T) =&gt; T),我只是试图修复第二个的顺序,同时尽可能少地破坏用户的代码。
  • 您可以:1) 如果可能的话,向第二个 foo 添加一些附加参数 - 或 - 2) 通过将第二个参数转换为 union type "Int or String" 然后将其匹配到内部,将两个函数合并在一起合并foo
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-29
  • 1970-01-01
  • 1970-01-01
  • 2012-04-24
  • 1970-01-01
相关资源
最近更新 更多