Kotlin中泛型类的扩展函数

时间:2015-10-01 09:23:23

标签: 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
    }
}

更新

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

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

    init {
        "str" foo 42
    }
}

3 个答案:

答案 0 :(得分:17)

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

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

    init {
        "str" foo 42
    }
}

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

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

现在,StringAny的子类型,IntAny的子类型,因此此函数适用于参数。

但是在你的第一个例子中:

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> <{1}}的子类型,事实上除了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 } } 成员的可能签名施加了一些限制,但如果您对它们没有问题,则可以解决您的问题。

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

答案 1 :(得分:2)

我认为安德烈·布雷斯劳(Andrey Breslaw)接受的答案是正确的,但提供了错误的解决方案。

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

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

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

答案 2 :(得分:1)

您的方法plus期望参数与接收方具有相同的泛型类型参数T。因此,您无法将Foo<String>添加到Foo<Int>

如果您希望能够添加所有类型的Foo,则需要声明您的扩展功能,如下所示:

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