【发布时间】:2016-09-20 14:10:54
【问题描述】:
我想在泛型类型 T 上编写一个扩展方法,其中匹配的类型约束一个方法参数。
我想编译这个:
"Hello".thing("world")
但不是这个,因为 42 不是字符串:
"Hello".thing(42)
这个定义不成立,因为Any满足T
fun <T> T.thing(p: T) {}
【问题讨论】:
我想在泛型类型 T 上编写一个扩展方法,其中匹配的类型约束一个方法参数。
我想编译这个:
"Hello".thing("world")
但不是这个,因为 42 不是字符串:
"Hello".thing(42)
这个定义不成立,因为Any满足T
fun <T> T.thing(p: T) {}
【问题讨论】:
正如@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
Wrapper 甚至不需要捕获参数,只需返回并定义.get()。
改进@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) 中的任何一个都可以很好地过滤掉带有非字符串的调用。
【讨论】: