仅限消费者的 kotlin 泛型
kotlin generics for Consumer only
假设我有这个 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>
的内容,让编译器知道这实际上是 只是 一个 Consumer
,或者 in T
默认总是开启?
比我更了解 kotlin 的人可以为我指明正确的方向吗?
正如我在评论中所说,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>
假设我有这个 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>
的内容,让编译器知道这实际上是 只是 一个 Consumer
,或者 in T
默认总是开启?
比我更了解 kotlin 的人可以为我指明正确的方向吗?
正如我在评论中所说,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>