Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/kotlin/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Kotlin';当contains()取E时,s集是协变的吗?_Kotlin_Collections_Covariance - Fatal编程技术网

Kotlin';当contains()取E时,s集是协变的吗?

Kotlin';当contains()取E时,s集是协变的吗?,kotlin,collections,covariance,Kotlin,Collections,Covariance,我在研究几种编程语言的集合库中的协变和逆变,无意中发现了Kotlin的接口 记录如下: interface Set<out E> : Collection<E> () 因此,Set不是Set的“真实”子类型,因为Set.contains(5)与第二个而不是第一个一起工作 实际上调用contains方法甚至可以在运行时工作——只是我的实现永远不会被调用,它只会打印false 查看接口的源代码,结果发现这两个方法实际上声明为 abstract fun contains(el

我在研究几种编程语言的集合库中的协变和逆变,无意中发现了Kotlin的接口

记录如下:

interface Set<out E> : Collection<E>
()

因此,
Set
不是
Set
的“真实”子类型,因为
Set.contains(5)
与第二个而不是第一个一起工作

实际上调用contains方法甚至可以在运行时工作——只是我的实现永远不会被调用,它只会打印
false

查看接口的源代码,结果发现这两个方法实际上声明为

abstract fun contains(element: @UnsafeVariance E): Boolean
abstract fun containsAll(elements: Collection<@UnsafeVariance E>): Boolean
abstract fun contains(元素:@UnsafeVariance):布尔值
抽象元素(元素:集合):布尔值
这是怎么回事? 是否有一些特殊的编译器魔术集?
为什么没有在任何地方记录这一点?

out
修饰符的形式声明站点协方差忽略了一个有用的用例,即确保作为参数传递的实例通常可以在此处传递。
包含
函数就是一个很好的例子

Set.contains
的特殊情况下,
@UnsafeVariance
注释用于确保函数接受
E
的实例,因为将不属于
E
元素
传递到
contains
中毫无意义–所有
Set
的正确实现都将始终返回
false
Set
的实现不应存储传递给
contains
元素
,因此不应使用返回类型
E
从任何其他函数返回该元素。因此,正确实现的
在运行时不会违反方差限制

@UnsafeVariance
注释实际上会抑制编译器差异冲突,就像在
in
-位置使用
out
-投影类型参数一样

其动机最好描述在:

@UnsafeVariance
注释 有时我们需要在类中禁止声明站点差异检查。例如,要使
Set.contains
typesafe同时保持只读集的共变量,我们必须执行以下操作:

interface Set<out E> : Collection<E> {
     fun contains(element: @UnsafeVariance E): Boolean
}
接口集:集合{
乐趣包含(元素:@UnsafeVariance):布尔值
}
这就给
包含的
的实现者带来了一些责任,因为通过抑制此检查,元素的实际类型在运行时可能是任何类型,但有时需要实现方便的签名。请参阅下面有关集合类型安全性的更多信息

为此,我们在类型上引入了
@UnsafeVariance
注释。它被故意制作了很长时间,并站出来警告滥用它的人

博客文章的其余部分还明确提到,
的签名包含使用
@UnsafeVariance
提高类型安全性的


引入
@UnsafeVariance
的替代方案是保持
包含
接受
任何
,但是这个选项缺少对
包含的
调用的类型检查,该调用将检测到
元素的错误调用,这些调用由于不是
E

的实例而无法出现在集合中,但是我的实现怎么连这个参数都没有被调用呢?另外,我喜欢“contains的文档中甚至没有提到“contains的实现者的责任”。@Paŭloeberman是的,这似乎涉及到一些编译器魔法。如果您检查为
StringSet
实现生成的字节码,您会发现桥接方法
包含(Ljava/lang/Object;)Z
检查
元素
是否为
字符串
,如果不是,则立即返回false,而不调用重写的实现。请参阅。因此,我猜contains的
实现者的某些责任现在由编译器为内置集合接口处理。但是,我猜这是错误的签名中带有
@UnsafeVariance
的自定义类型未处理。让我检查一下。在
包含所有
的情况下,实现者仍有责任准确处理参数,因为在这种情况下,桥接器无法检查已擦除集合参数的实际类型。
abstract fun contains(element: @UnsafeVariance E): Boolean
abstract fun containsAll(elements: Collection<@UnsafeVariance E>): Boolean
interface Set<out E> : Collection<E> {
     fun contains(element: @UnsafeVariance E): Boolean
}