【问题标题】:Removing ambiguity of overloaded method definition消除重载方法定义的歧义
【发布时间】:2015-11-25 11:44:09
【问题描述】:

编译器被重载的方法定义弄糊涂了,我找不到充分阐明我的意图的方法。

我有以下代码:

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],我仍然不明白所谓的歧义的原因,并且不想引入额外的价值。有什么说明吗?

【问题讨论】:

    标签: scala compiler-errors overloading ambiguous


    【解决方案1】:

    首先,重要的是要了解尾随下划线是为了防止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)
    

    【讨论】:

    • +1 是的,带有 args 变体的 lambda 也可以,谢谢你的提示,moem。如果编译器错误是故意的,我本以为它会推动我走向正确的方向,但我看不出它是关于什么设计原则的。如果可以通过某种方式提供要扩展的方法的类型来解决歧义,那就太酷了——笨拙的版本find[QueryParams]: List[ResultTuple] _
    • @kostja 因为没有指定中间类型,所以在编写find _ 时,编译器应该推断类型为QueryParams => List[ResultTuple](如您所料)还是应该为(QueryParams, U => T) => List[ResultTuple] ?请注意,结尾的下划线不代表单个参数,它只是将方法提升为函数。
    猜你喜欢
    • 2022-07-26
    • 1970-01-01
    • 1970-01-01
    • 2013-08-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多