Extension functions for generic classes in Kotlin

后端 未结 3 1401
南笙
南笙 2020-12-15 21:15

What\'s wrong with my extension function below

class Foo {
    fun  Foo.plus(that: Foo): Foo = throw Exception()         


        
3条回答
  •  伪装坚强ぢ
    2020-12-15 21:47

    The issue is at the very heart of how generics work.

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

    This works, because the compiler can find a T that fits both the function signature and the arguments: it is Any, and the function is turned into this one:

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

    Now, String is a subtype of Any, Int is a subtype of Any, so this function is applicable to the arguments.

    But in your first example:

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

    It's all different. There's no such T. Let's be naïve and try Any:

    fun Foo.plus(that: Foo): Foo = ...
    

    Now, Foo is invariant in T, so Foo is not a subtype of Foo, and in fact there's no type T other than Int that would make Foo a supertype of Foo. So, T must be exactly Int, but it also must be exactly String by the same logic (because of the second argument), so there's no solution, and the function is not applicable.

    You could make it work by making Foo co-variant in T:

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

    This imposes some limitations on possible signatures of members of Foo, but if you are OK with them, it fixes your issue.

    Have a look at this link for more details: http://kotlinlang.org/docs/reference/generics.html

提交回复
热议问题