Kotlin中泛型类的扩展函数 [英] Extension functions for generic classes in Kotlin
问题描述
下面的扩展函数有什么问题?
class Foo< T> {
fun< T> Foo T .plus(即:Foo T):Foo T。 = throw Exception()
init {
Foo< Int>()+ Foo< String>()//接收者类型为Foo< T>是必需的
$ b
更新
我想知道为什么它与常规扩展函数不同,其中T成功推断为 Any
,并且希望实现同样的行为,例如。 G。 T推断为Foo< Any>
class Foo {
fun< T> T.foo(that:T):T = throw Exception()
init {
strfoo 42
}
}
code>
这个问题是泛型工作的核心。 b
$ b
class Foo {
fun< T> T.foo(that:T):T = throw Exception()
init {
strfoo 42
}
}
code>
这样做可行,因为编译器可以找到一个适合两者的 T
函数签名和参数:它是任何
,并且函数变成这个函数:
fun Any.foo(that:Any):Any = ...
现在, String
是任何
的子类型, Int
是一个子类型任何
,所以这个函数适用于参数。
但是在你的第一个例子中:
class Foo< T> {
fun< T> Foo T .plus(即:Foo T):Foo T。 = throw Exception()
init {
Foo< Int>()+ Foo< String>()//接收器类型为Foo< T>是必需的
完全不同。没有这样的 T
。让我们天真,尝试任何
:
fun Foo< Any> ;.加(即:Foo< Any>):Foo< Any> = ...
现在, Foo
是 T
,所以 Foo< Int>
不是 > Foo< Any>
的子类型,事实上没有类型 T ,而不是
Int
会使 Foo< T>
超类型 Foo< Int>
。因此, T
必须完全是 Int
,但它也必须完全是 String
由相同的逻辑(因为第二个参数),所以没有解决方案,该功能是不适用的。
你可以通过制作 Foo
co-variant 在 T
中:
class Foo< out T> {
fun< T> Foo T .plus(即:Foo T):Foo T。 = throw Exception()
init {
Foo< Int>()+ Foo< String>()//接收器类型为Foo< T>是必需的
code
$ b 这对成员的可能签名施加了一些限制 Foo
,但是如果你确定,它可以解决你的问题。
查看此链接了解更多详情: http:/ /kotlinlang.org/docs/reference/generics.html
What's wrong with my extension function below
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
}
}
Update
I wonder why it's different than regular extension functions, where T successfully gets inferred as Any
and would like to achieve the same behavior, e. g. T to get inferred as Foo<Any>
class Foo {
fun <T> T.foo(that: T): T = throw Exception()
init {
"str" foo 42
}
}
解决方案 The issue is at the very heart of how generics work.
class Foo {
fun <T> 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<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
}
}
It's all different. There's no such T
. Let's be naïve and try Any
:
fun Foo<Any>.plus(that: Foo<Any>): Foo<Any> = ...
Now, Foo
is invariant in T
, so Foo<Int>
is not a subtype of Foo<Any>
, and in fact there's no type T
other than Int
that would make Foo<T>
a supertype of Foo<Int>
. 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<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
}
}
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
这篇关于Kotlin中泛型类的扩展函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!