如何限制Kotlin扩展函数参数与扩展类型相同?
我想在泛型类型T上写一个扩展方法,其中匹配类型约束一个方法参数。
我想这个编译:
"Hello".thing("world")
但不是这样,因为42不是一个字符串:
"Hello".thing(42)
这个定义不起作用,因为T满足Any
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")
据我所知,这在Kotlin 1.0中是不可能的。 跟踪器( 第一 , 第二 )有几个类似用例的问题,第一个提出的解决方案在未来也可能会有所帮助。
改进@ miensol的解决方法,并使其在视觉上与函数调用相同:
val <T> T.foo: (T) -> SomeType get() = { other -> ... }
这是一个扩展属性,它提供了一个lambda,可以立即使用相同类型T
的参数调用,如下所示:
"abc".foo(1) // Fail "abc".foo("def") // OK
不幸的是, 在编译器中似乎有一个错误,它会阻止你编写"abc".thing("abc")
,但是不管是"abc".thing.invoke("abc")
和("abc".thing)("abc)
很好地工作,并过滤掉非字符串的调用。