Kotlin中泛型类的扩展函数

Yar*_*lav 11 generics kotlin kotlin-extension

我的扩展功能在下面有什么问题

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
    }
}
Run Code Online (Sandbox Code Playgroud)

更新

我想知道为什么它与常规扩展函数不同,其中T成功地被推断为Any并且想要实现相同的行为,例如T被推断为Foo <Any>

class Foo {
    fun <T> T.foo(that: T): T = throw Exception()

    init {
        "str" foo 42
    }
}
Run Code Online (Sandbox Code Playgroud)

And*_*lav 19

问题是仿制药如何运作的核心问题.

class Foo {
    fun <T> T.foo(that: T): T = throw Exception()

    init {
        "str" foo 42
    }
}
Run Code Online (Sandbox Code Playgroud)

这是有效的,因为编译器可以找到T适合函数签名和参数的东西:它是Any,并且函数变成了这个:

fun Any.foo(that: Any): Any = ...
Run Code Online (Sandbox Code Playgroud)

现在,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
    }
}
Run Code Online (Sandbox Code Playgroud)

这都是不同的.没有这样的T.让我们天真并尝试Any:

fun Foo<Any>.plus(that: Foo<Any>): Foo<Any> = ...
Run Code Online (Sandbox Code Playgroud)

现在,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
    }
}
Run Code Online (Sandbox Code Playgroud)

这对成员的可能签名施加了一些限制Foo,但是如果你对它们没问题,它会修复你的问题.

有关更多详细信息,请查看此链接:http://kotlinlang.org/docs/reference/generics.html


小智 6

我认为 Andrey Breslaw 接受的答案是正确的,但提供了不正确的解决方案。

编译器只需要被告知为提供的泛型类型参数推断公共超类型,即,只要 Foo 的泛型类型参数共享一个公共超类型(它们总是会),就使用它。喜欢:

operator fun <T, R: T, S: T> Foo<R>.plus(that: Foo<S>): Foo<T> = throw Exception()
Run Code Online (Sandbox Code Playgroud)

现在,如果类型不匹配,则返回的 Foo 的结果泛型类型参数将根据需要进行扩展,但操作本身是合法的,不会引入协方差。