【问题标题】:Extension functions for generic classes in KotlinKotlin 中泛型类的扩展函数
【发布时间】:2015-10-01 09:23:22
【问题描述】:

下面我的扩展功能有什么问题

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

class Foo {
    fun <T> T.foo(that: T): T = throw Exception()

    init {
        "str" foo 42
    }
}

【问题讨论】:

  • >>>“我想知道为什么不一样”@Yaroslav 常规函数没有+no+ 的区别。这只是子类型 Foo&lt;A&gt;Foo&lt;B&gt; 的问题,其中 A 是 B 的子类型。在 Java 中,它需要狂野转换。不确定 Scala,我相信他们有 Foo[+T] 用于相同目的

标签: generics kotlin kotlin-extension


【解决方案1】:

问题是泛型工作方式的核心。

class Foo {
    fun <T> T.foo(that: T): T = throw Exception()

    init {
        "str" foo 42
    }
}

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

fun Any.foo(that: Any): Any = ...

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

但在你的第一个例子中:

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

现在,FooT 中是不变量,所以Foo&lt;Int&gt; 不是Foo&lt;Any&gt; 的子类型,事实上@987654338 没有类型@ 除了Int,这将使Foo&lt;T&gt; 成为Foo&lt;Int&gt; 的超类型。所以T一定是Int,但同样的逻辑也一定是String(因为第二个参数),所以没有解决办法,函数不适用。

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

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

【讨论】:

    【解决方案2】:

    我认为 Andrey Breslaw 接受的答案是正确的,但提供了不正确的解决方案。

    只需要告诉编译器为提供的泛型类型参数推断公共超类型,即,只要 Foo 的泛型类型参数共享一个公共超类型(并且它们总是会),使用它。喜欢:

    operator fun <T, R: T, S: T> Foo<R>.plus(that: Foo<S>): Foo<T> = throw Exception()
    

    现在,如果类型不匹配,返回的 Foo 的结果泛型类型参数将根据需要扩展,但操作本身是合法的,不会引入协方差。

    【讨论】:

      【解决方案3】:

      您的方法plus 期望参数具有与接收者相同的泛型类型参数T。因此,您不能将Foo&lt;String&gt; 添加到Foo&lt;Int&gt;

      如果你希望能够添加所有类型的Foo,那么你需要像这样声明你的扩展函数:

      operator fun <T,R> Foo<T>.plus(that: Foo<R>): Foo<T> = throw Exception()
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-12-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多