【问题标题】:How to deal with an overload resolution ambiguity of functions with generics?如何使用泛型处理函数的重载解析歧义?
【发布时间】:2017-04-05 00:19:45
【问题描述】:

考虑这个类有两个函数,一个带有Int 参数,另一个带有一个通用函数:

class C<K, V> {
    // ...

    operator fun f(index: Int): Pair<K, V> = ...
    operator fun f(key: K): V = ...
}

当参数化为C&lt;Int, SomeType&gt;时,KInt,两个函数都匹配调用,导致报错:

val m = C<Int, SomeType>()
m.f(1)

重载分辨率不明确。所有这些功能都匹配:

  • public final fun f(index: Int): SomeType 定义在 C
  • public final fun f(key: Int): Pair&lt;Int, SomeType&gt;? 定义在 C

在这种情况下,我如何拨打我想要的f

【问题讨论】:

    标签: generics kotlin ambiguous overload-resolution


    【解决方案1】:

    如果你有幸拥有不同的函数参数名称,使用named arguments 就可以了:

    m.f(index = 1) // calls f(index: Int)
    m.f(key = 1)   // calls f(key: K)
    

    否则,如果参数名称相同(或在 Java 中定义),一种可能的解决方法是执行 unchecked casts 以使编译器选择所需的选项:

    • 拨打f(index: Int),可以使用

      @Suppress("UNCHECKED_CAST")
      val s = (m as C<*, SomeType>).f(1) as Pair<Int, SomeType>
      

      转换为C&lt;*, SomeType&gt;makes K equivalent to in Nothing, out Any,意味着f(key: K)没有有效的参数,所以调用自然会解析为f(index: Int),但是你需要把结果转换回来,否则就是@987654332 @。

    • 要呼叫f(key: K),请使用:

      @Suppress("UNCHECKED_CAST")
      val s = (m as C<Any, SomeType>).f(1 as Any)
      

      同样,转换为C&lt;Any, SomeType&gt; 会将所需函数的签名更改为f(key: Any),并调用它,只需将1 向上转换为Any

    在几个类型参数冲突的情况下都是一样的(例如KV都是SomeTypef(key: K)f(value: V)),只需使用命名参数或将对象强制转换为禁止其中一项功能 (in Nothing) 或使其接受 Any

    【讨论】:

      【解决方案2】:

      Kotlin 标准库使用约定 fun fAt(index: Int) 来解决此类情况。

      【讨论】:

      • 确实如此,但这需要提前考虑设计类C,以防止可能与替代泛型发生签名冲突。如果你遇到这样的类并且无法重命名它的函数,你必须求助于@hotkey's answer中的通用技巧。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-08-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多