消除重载方法定义的歧义

时间:2015-11-25 11:44:10

标签: scala compiler-errors overloading ambiguous

编译器因为重载方法定义而感到困惑,我找不到充分澄清我的意图的方法。

我有以下代码:

val part: (QueryParams) => List[ResultMap] = (partOf.find _).andThen(makeMap)

find方法已超载:

def find(params: QueryParams): List[U] = ...
def find(params: QueryParams, flattener: U => T): List[T] = ...

只要有一个find的定义,代码就可以正常运行。由于我必须使用2个参数添加第二个find定义,因此编译器会生成此错误:

Error:(15, 31) ambiguous reference to overloaded definition, both method find in trait DataFetcher of type (params: ...QueryParams)List[...Parser] and method find in trait DataFetcher of type (params: ...QueryParams, flattener: ...Parser => ...ResultTuple)List[...ResultTuple] match expected type ? val part: Fetcher = (partOf.find _).andThen(makeMap) ^

恕我直言,没有歧义。 part的类型定义为接受QueryParams类型的一个参数。只有一种方法可以接受单个QueryParamsUT是不同的类型,makeMap期望List[U]不涉及隐含,默认值或变量。

有没有办法进一步澄清我对编译器的意图?

编辑:消除歧义的一种方法是引入中间值,澄清eta扩展的预期类型:

val find: (QueryParams) => List[ResultTuple] = partOf.find _
val part: (QueryParams) => List[ResultMap] = find andThen makeMap

但是由于makeMap只接受List[ResultTuple],我不知道所谓的歧义的原因,并且宁愿不引入额外的价值。有任何澄清吗?

1 个答案:

答案 0 :(得分:2)

首先,重要的是要理解尾随下划线是故意设计决定以防止programmer mistakes。唯一的例外是显式声明类型。

这是一个说明这一点的例子。

object A {
  def add(a: Int)(b:Int): Int = a + b
  val x: Int => Int = add(5) // compiles fine
  val y = add(5) // produces a compiler error
}

这同样适用于您的问题。因为您没有指定中间类型,所以当您编写find _时,编译器是否应该将类型推断为QueryParams => List[ResultTuple](如您所料)或应该是(QueryParams, U => T) => List[ResultTuple]?请注意,尾随下划线不代表单个参数,它只是将方法提升为函数。当声明类型时,您可以删除尾随下划线并将find写在您写入find _的位置。

我从您的编辑中看到您发现具有声明类型的中间值有效。澄清你意图的另一种(略显笨重的)方法如下。

val part: (QueryParams) => List[ResultMap] = (x => partOf.find(x)).andThen(makeMap)