[英]Extension functions for generic classes in Kotlin
我下面的扩展功能有什么问题
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>
的子类型,实际上除了Int
之外没有其他类型T
会使Foo<T>
成为Foo<Int>
的超类型。 因此, T
必须完全是Int
,但它也必须完全是String
,逻辑相同(因为第二个参数),因此没有解决方案,并且该函数不适用。
您可以通过在T
中使Foo
协变来使其工作:
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
我认为 Andrey Breslaw 接受的答案是正确的,但提供了不正确的解决方案。
编译器只需要被告知为提供的泛型类型参数推断公共超类型,即,只要 Foo 的泛型类型参数共享一个公共超类型(它们总是会),就使用它。 像:
operator fun <T, R: T, S: T> Foo<R>.plus(that: Foo<S>): Foo<T> = throw Exception()
现在,如果类型不匹配,则返回的 Foo 的结果泛型类型参数将根据需要进行扩展,但操作本身是合法的,不会引入协方差。
您的方法plus
期望参数具有与接收器相同的泛型类型参数T
因此,您不能将Foo<String>
添加到Foo<Int>
。
如果您希望能够添加所有类型的Foo
,那么您需要像这样声明您的扩展函数:
operator fun <T,R> Foo<T>.plus(that: Foo<R>): Foo<T> = throw Exception()
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.