为什么在功能参数中的反类型参数在"out"中被考虑?位置? [英] Why are contravariant type parameters in function parameters considered in "out" position?

查看:116
本文介绍了为什么在功能参数中的反类型参数在"out"中被考虑?位置?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我很难用英语来描述,但这是问题所在:

Hard for me to describe in english, but here's the issue:

class Consumer<in T> {
    fun consume(t: T) {}
}

class Accepter<in T>() {
    // ERROR: Type parameter T is declared as 'in' but occurs in 'out' position in type Consumer<T>
    fun acceptWith(value: T, consumer: Consumer<T>) {}
}

可以这样修复:

fun <U : T> acceptWith(value: T, consumer: Consumer<U>) {}

但是我不明白这个问题.允许Consumer<T>似乎并不安全.有人可以解释吗?

But I don't understand the issue. It doesn't seem unsafe to allow Consumer<T>. Can someone explain this?

推荐答案

本身允许输入的函数参数在逻辑上等效于函数的返回值,这些函数的值显然处于出"位置.

Function parameters which themselves allow input are logically equivalent to return values for a function, which are obviously in "out" position.

考虑以下简单示例:

interface Worker<in T> {
    fun work(output: Consumer<T>)
}

从逻辑上讲,它等同于

interface Worker<in T> {
    fun work(): T
}

不论哪种情况,

work()都可以输出一个值.

work() can output a value in either case.

此失败的示例:

fun bad(anyWorker: Worker<Any>) {
    val stringWorker: Worker<String> = anyWorker
    stringWorker.work(Consumer { value: String -> /* value could be Any since it came from anyWorker! */ })
}

但是,我们可以通过为函数引入新的类型参数来解决此问题:

However, we can solve this by introducing a new type parameter for the function:

interface Worker<in T> {
    fun <U : T> work(output: Consumer<U>)
}

现在,将仅允许work()调用具有消费者必须能够使用的某些特定子类型TConsumer.例如,让我们想象一下工作像原始问题一样接受了另一个论证,并且实际上做了一些事情:

Now, work() will only be allowed to call the Consumer with some specific subtype of T that the consumer must be able to consume. For example, lets imagine that work takes another argument, as in the original question, and actually does something:

class Worker<in T> {
    private val inputs = mutableListOf<T>()

    fun <U : T> work(input: U, output: Consumer<U>) {
        inputs += input
        output.accept(input)
    }
}

通过引入类型参数U,我们可以确保inputoutput彼此一致,但仍允许Worker<Any>扩展Worker<String>.

By introducing the type parameter U, we can ensure that input and output are consistent with respect to each other, but still allow Worker<Any> to extend Worker<String>.

这篇关于为什么在功能参数中的反类型参数在"out"中被考虑?位置?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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