如何限制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)很好地工作,并过滤掉非字符串的调用。