Функции расширения для общих классов в Котлине

Что случилось с моей функцией расширения ниже

class Foo<T> { fun <T> Foo<T>.plus(that: Foo<T>): Foo<T> = throw Exception() init { Foo<Int>() + Foo<String>() // A receiver of type Foo<T> is required } } 

Обновить

Интересно, почему это отличается от регулярных функций расширения, где T успешно выводится как Any и хочет достичь такого же поведения, например T, чтобы получить вывод как Foo <Any>

 class Foo { fun <T> T.foo(that: T): T = throw Exception() init { "str" foo 42 } } 

Проблема заключается в том, как работают дженерики.

 class Foo { fun <T> T.foo(that: T): T = throw Exception() init { "str" foo 42 } } 

Это работает, потому что компилятор может найти T который соответствует как сигнатуре функции, так и аргументам: это Any , и функция превращается в эту:

 fun Any.foo(that: Any): Any = ... 

Теперь String является подтипом Any , Int является подтипом Any , поэтому эта функция применима к аргументам.

Но в вашем первом примере:

 class Foo<T> { fun <T> Foo<T>.plus(that: Foo<T>): Foo<T> = throw Exception() init { Foo<Int>() + Foo<String>() // A receiver of type Foo<T> is required } } 

Все по-другому. Такого T . Давайте будем наивными и попробуем Any :

 fun Foo<Any>.plus(that: Foo<Any>): Foo<Any> = ... 

Теперь Foo инвариантен в T , поэтому Foo<Int> не является подтипом Foo<Any> , и на самом деле нет типа T кроме Int что сделало бы Foo<T> супертипом Foo<Int> . Итак, T должен быть точно Int , но он также должен быть точно String по той же логике (из-за второго аргумента), поэтому нет решения, и функция не применима.

Вы можете заставить его работать, сделав совместный вариант Foo в T :

 class Foo<out T> { fun <T> Foo<T>.plus(that: Foo<T>): Foo<T> = throw Exception() init { Foo<Int>() + Foo<String>() // A receiver of type Foo<T> is required } } 

Это накладывает некоторые ограничения на возможные подписи членов Foo , но если вы в порядке с ними, это исправляет вашу проблему.

Посмотрите на эту ссылку для получения дополнительной информации: http://kotlinlang.org/docs/reference/generics.html

Ваш метод plus ожидает, что параметр будет иметь тот же общий тип параметра T что и приемник. Следовательно, вы не можете добавить Foo<String> в Foo<Int> .

Если вы хотите добавить все типы Foo , вам нужно объявить свою функцию расширения следующим образом:

 operator fun <T,R> Foo<T>.plus(that: Foo<R>): Foo<T> = throw Exception()