我想在泛型类型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")
改善@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)做工精良又过滤掉非字符串电话。