Kotlin通用药品(仅限消费者)

时间:2018-09-05 19:31:38

标签: java generics kotlin kotlin-generics

让我说我有这个java示例:

interface Sink<T> {
    void accumulate(T t);
}

public static <T> void drainToSink(Collection<T> collection, Sink<? super T> sink) {
    collection.forEach(sink::accumulate);
}

注意如何将第二个参数声明为? super T。我需要这个,因为我想这样调用该方法:

Sink<Object> sink = .... // some Sink implementation
Collection<String> strings = List.of("abc");
drainToSink(strings, sink);

现在,我正在尝试使用Kotlin(我经验很少)实现相同的目的:

interface Sink<T> {
    fun accumulate(t: T)
}

fun <T> drainToSink(collection: List<T>, sink: Sink<T>) {
   ....
}

现在我正在尝试使用它:

fun main(args: Array<String>) {

     val sink = object : Sink<Any> {
         override fun accumulate(any: Any) {  }
     }

     val strings = emptyList<String>()
     drainToSink(strings, sink)
}

足够有趣的是,这不会失败(除非我对Kotlin的了解很少)。

我真的希望我需要在声明中添加类似Sink<in T>之类的内容,以使编译器知道这实际上是 just 一个Consumer,或者是{{ 1}}始终处于默认状态?

能比我更了解科特琳的人将我指向正确的方向吗?

1 个答案:

答案 0 :(得分:3)

就像我在评论中说的,T在这里被推断为Any。这就是我让我的IDE向drainToSink调用添加显式类型参数时看到的。

由于kotlin的List严格来说是生产者,因为它是不可变的,所以将其类型参数声明为out E。您将List<Any>作为drainToSink的参数类型,可以为此分配一个List<String>

val strings = emptyList<String>()
val x: List<Any> = strings // works

如果将第一个参数类型更改为没有协变类型参数的MutableList<T>,则示例确实失败:

fun <T> drainToSink(collection: MutableList<T>, sink: Sink<T>) {
    ....
}
val strings = emptyList<String>()
drainToSink(strings, sink) // type mismatch: Required: MutableList<Any>, Found: List<String>