我的扩展功能在
下面出了什么问题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
}
}
答案 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 = ...
现在,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>
<{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()