Как ограничить параметр функции расширения Kotlin таким же, как и расширенный?

Я хочу написать метод расширения для общего типа T, где подобранный тип ограничивает параметр метода.

Я хочу, чтобы это скомпилировалось:

"Hello".thing("world") 

Но не это, поскольку 42 не является Строкой:

 "Hello".thing(42) 

Это определение не работает, так как T удовлетворено Any

 fun <T> T.thing(p: T) {} 

Как уже упоминал @ Александр Александрович Удалов, это невозможно сделать напрямую, но есть способ, которым вы определяете метод расширения для другого типа:

 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 -> ... } 

Это свойство расширения, которое предоставляет лямбду, которая может быть немедленно вызвана с аргументом одного типа T следующим образом:

 "abc".foo(1) // Fail "abc".foo("def") // OK 

К сожалению, в компиляторе есть ошибка, которая мешает вам писать "abc".thing("abc") , но либо "abc".thing.invoke("abc") и ("abc".thing)("abc) хорошо работают и отфильтровывают вызовы с не-строками.