代码之家  ›  专栏  ›  技术社区  ›  Eugene

仅限消费者使用的kotlin泛型

  •  4
  • Eugene  · 技术社区  · 6 年前

    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实现同样的目标(我对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)
    }
    

    我真的希望我需要在声明中添加一些 Sink<in T> 让编译器知道这实际上是 只是 Consumer ,或是 in T

    有谁比我更了解科特林,能给我指出正确的方向吗?

    1 回复  |  直到 6 年前
        1
  •  3
  •   Jorn Vernee    6 年前

    就像我在评论中说的, T 被推断为 Any drainToSink 打电话。

    自从kotlin List 严格来说,它是一个生产者,因为它是不可变的,所以它将其类型参数声明为 out E List<Any> 作为的参数类型 ,分配一个 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>
    
    推荐文章