【问题标题】:How do I constrain a Kotlin extension function parameter to be the same as the extended type?如何将 Kotlin 扩展函数参数约束为与扩展类型相同?
【发布时间】:2016-09-20 14:10:54
【问题描述】:

我想在泛型类型 T 上编写一个扩展方法,其中匹配的类型约束一个方法参数。

我想编译这个:

"Hello".thing("world")

但不是这个,因为 42 不是字符串:

"Hello".thing(42)

这个定义不成立,因为Any满足T

fun <T> T.thing(p: T) {}

【问题讨论】:

    标签: generics kotlin


    【解决方案1】:

    正如@Alexander Udalov 所述,无法直接执行此操作,但有一种解决方法,您可以在其他类型上定义扩展方法,如下所示:

    data class Wrapper<T>(val value: T)
    
    val <T> T.ext: Wrapper<T> get() = Wrapper(this)
    
    fun <T> Wrapper<T>.thing(p: T) {
        println("value = $value, param = $p")
    }
    

    通过上面的编译:

    "abc".ext.thing("A")
    

    但下一个失败

    "abc".ext.thing(2)
    

    与:

    Kotlin: Type inference failed: Cannot infer type parameter T in fun <T> Wrapper<T>.thing(p: T): Unit
    None of the following substitutions
    receiver: Wrapper<String>  arguments: (String)
    receiver: Wrapper<Int>  arguments: (Int)
    can be applied to
    receiver: Wrapper<String>  arguments: (Int)
    

    正如@hotkey 所建议的,似乎应该可以通过以下扩展属性避免显式Wrapper 类型:

    val <T> T.thing: (T) -> Any? get() = { println("extension body") }
    

    然后将其用作"abc".thing("A"),但它也失败了。令人惊讶的是,以下内容确实编译了"abc".thing.invoke("A")

    【讨论】:

    • 可以定义一个扩展属性并将invoke() 函数添加到Wrapper 以使此解决方法在语法上与函数调用相同,但编译器中似乎有一个错误阻止了我从这样做。
    • 有趣的是,即使("abc".foo)("abc") 也有效。 :D
    • 我认为考虑到这个错误,这将被接受,但感谢@hotkey 的工作
    • 实际上Wrapper 甚至不需要捕获参数,只需返回并定义.get()
    • 这在 Kotlin 1.4 中不再有效。它只会编译。
    【解决方案2】:

    据我所知,这在 Kotlin 1.0 中是不可能的。跟踪器中存在几个关于类似用例的问题(firstsecond),第一个中提出的解决方案将来也可能会有所帮助。

    【讨论】:

      【解决方案3】:

      改进@miensol 的解决方法并使其在视觉上与函数调用相同:

      val <T> T.foo: (T) -> SomeType get() = { other -> ... }
      

      这是一个提供 lambda 的扩展属性,可以使用相同类型的参数立即调用 T,如下所示:

      "abc".foo(1) // Fail
      "abc".foo("def") // OK
      

      不幸的是,seems to be a bug in the compiler 会阻止您编写"abc".thing("abc"),但"abc".thing.invoke("abc")("abc".thing)("abc) 中的任何一个都可以很好地过滤掉带有非字符串的调用。

      【讨论】:

        猜你喜欢
        • 2019-03-22
        • 1970-01-01
        • 2020-05-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多