如何将Kotlin扩展函数参数约束为与扩展类型相同?

Dun*_*gor 18 generics kotlin

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

我希望这个编译:

"Hello".thing("world")
Run Code Online (Sandbox Code Playgroud)

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

"Hello".thing(42)
Run Code Online (Sandbox Code Playgroud)

这个定义不起作用,因为T满足 Any

fun <T> T.thing(p: T) {}
Run Code Online (Sandbox Code Playgroud)

mie*_*sol 13

正如@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")
}
Run Code Online (Sandbox Code Playgroud)

以上编译如下:

"abc".ext.thing("A")
Run Code Online (Sandbox Code Playgroud)

但下一次失败了

"abc".ext.thing(2)
Run Code Online (Sandbox Code Playgroud)

有:

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)
Run Code Online (Sandbox Code Playgroud)

正如@hotkey所建议的那样,似乎应该可以避免Wrapper使用具有以下扩展属性的显式类型:

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

然后使用它,"abc".thing("A")它也失败了.令人惊讶的是,以下编译"abc".thing.invoke("A")


Ale*_*lov 10

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


hot*_*key 5

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

val <T> T.foo: (T) -> SomeType get() = { other -> ... }
Run Code Online (Sandbox Code Playgroud)

这是提供lambda的扩展属性,可以使用T类似类型的参数立即调用该lambda :

"abc".foo(1) // Fail
"abc".foo("def") // OK
Run Code Online (Sandbox Code Playgroud)

不幸的是,似乎是在编译器中的错误,防止你的写作"abc".thing("abc"),但任何的"abc".thing.invoke("abc")("abc".thing)("abc)做工精良又过滤掉非字符串电话。