Kotlin中泛型类的扩展函数 [英] Extension functions for generic classes in Kotlin

查看:179
本文介绍了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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆