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

查看:25
本文介绍了Kotlin 中泛型类的扩展函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我下面的扩展函数有什么问题

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
    }
}

更新

我想知道为什么它与常规扩展函数不同,其中 T 成功地被推断为 Any 并希望实现相同的行为,例如.G.T 被推断为 Foo

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
    }
}

这是可行的,因为编译器可以找到一个既适合函数签名又适合参数的T:它是Any,而函数就变成了这个:

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 = ...

现在,StringAny的子类型,IntAny的子类型,所以这个函数适用于参数.

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
    }
}

一切都不一样了.没有这样的 T.让我们天真地尝试Any:

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> = ...

现在,FooT 中是 不变的,所以 Foonot Foo 的子类型,实际上除了 Int 之外没有任何类型 T 可以使 Foo<;T> Foo 的超类型.所以,T 必须完全是 Int,但它也必须完全是 String,按照相同的逻辑(因为第二个参数),所以有无解,功能不适用.

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.

您可以通过在 T 中制作 Foo co-variant 来使其工作:

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
    }
}

这对 Foo 成员的可能签名施加了一些限制,但如果您同意他们,它就可以解决您的问题.

This imposes some limitations on possible signatures of members of Foo, but if you are OK with them, it fixes your issue.

查看此链接了解更多详情:http://kotlinlang.org/docs/reference/generics.html

Have a look at this link for more details: http://kotlinlang.org/docs/reference/generics.html

这篇关于Kotlin 中泛型类的扩展函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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