编译器因为重载方法定义而感到困惑,我找不到充分澄清我的意图的方法。
我有以下代码:
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
类型的一个参数。只有一种方法可以接受单个QueryParams
。 U
和T
是不同的类型,makeMap
期望List[U]
不涉及隐含,默认值或变量。
有没有办法进一步澄清我对编译器的意图?
编辑:消除歧义的一种方法是引入中间值,澄清eta扩展的预期类型:
val find: (QueryParams) => List[ResultTuple] = partOf.find _
val part: (QueryParams) => List[ResultMap] = find andThen makeMap
但是由于makeMap
只接受List[ResultTuple]
,我不知道所谓的歧义的原因,并且宁愿不引入额外的价值。有任何澄清吗?
答案 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)