@uncheckedVariance
可用于弥合Scala的声明站点差异注释和Java的不变泛型之间的鸿沟。
scala> import java.util.Comparator
import java.util.Comparator
scala> trait Foo[T] extends Comparator[T]
defined trait Foo
scala> trait Foo[-T] extends Comparator[T]
<console>:5: error: contravariant type T occurs in invariant position in type [-T]java.lang.Object with java.util.Comparator[T] of trait Foo
trait Foo[-T] extends Comparator[T]
^
scala> import annotation.unchecked._
import annotation.unchecked._
scala> trait Foo[-T] extends Comparator[T @uncheckedVariance]
defined trait Foo
这表明java.util.Comparator自然是反变量的,即类型参数T
出现在参数中,而永远不会出现在返回类型中。
这提出了一个问题:为什么它也用于Scala集合库中,而该库不是从Java接口扩展的?
trait GenericTraversableTemplate[+A, +CC[X] <: Traversable[X]] extends HasNewBuilder[A, CC[A] @uncheckedVariance]
此注释的有效用途是什么?
问题是,GenericTraversableTemplate使用了两次:一次用于可变集合(其类型参数应为不变的),一次用于不可变集合(协方差始终为国王)。
GenericTraversableTemplate的类型检查假定A类型参数是协方差还是不变。但是,当我们以可变特征继承它时,我们必须选择不变性。相反,我们希望在不可变子类中使用协方差。
由于我们无法在GenericTraversableTemplate中抽象化方差注释(尚未;-),因此我们可以根据子类将其实例化为任意一个,因此我们必须诉诸强制转换(@uncheckVariance本质上是一种-投)。为了进一步阅读,我推荐我的论文(对不起;-))或我们最近的bitrot paper
在我的论文中,我描述了一种演算Scalina,该演算具有边界和方差注释作为同类语言的一部分(更早的版本也可以作为workshop paper使用)。与该讨论的相关性是我要开发此演算的下一步:在该演算的基础上再建一层,以便您可以抽象边界(简单)和方差注释(使我头晕)。实际上,您不仅会在此处添加1个额外的层,还要对多态结构进行泛化,以便它们可以在所有级别上使用,并将“属性”(边界,方差注释,必需的隐式参数等)变成常规类型。带有特殊种类的东西,这些都是抽象的。
[属性是类型”这个想法由Edsko de Vries在唯一性类型的上下文中很好地解释了。
Uniqueness Typing Simplified,Edsko de Vries,Rinus Plasmeijer和David Abrahamson。在Olaf Chitil,ZoltánHorváth和ViktóriaZsók(编辑)中:IFL 2007,LNCS 5083,第201-218页,2008年。
摘要:我们提出一种唯一性类型比两者都简单的系统清洁的独特性系统和我们之前提出的系统。新的类型系统简单易懂实施并添加到现有编译器,并且可以轻松扩展具有高级功能,例如更高等级类型和隐含性。我们描述我们在Morrow中的实现,实验性功能语言具有这两个功能。最后,我们证明核心类型的合理性关于按需调用lambda演算。
我又发现使用@uncheckedVariance的时间-一种返回抽象类型参数默认值的综合方法:
M:\>scala -Xprint:typer -e "class C { def p[T >: Null](t: T = null) = t }"
[[syntax trees at end of typer]]// Scala source: (virtual file)
package <empty> {
final object Main extends java.lang.Object with ScalaObject {
def this(): object Main = {
Main.super.this();
()
};
def main(argv: Array[String]): Unit = {
val args: Array[String] = argv;
{
final class $anon extends scala.AnyRef {
def this(): anonymous class $anon = {
$anon.super.this();
()
};
class C extends java.lang.Object with ScalaObject {
<synthetic> def p$default$1[T >: Null <: Any]: Null @scala.annotation.unchecked.uncheckedVariance = null;
def this(): this.C = {
C.super.this();
()
};
def p[T >: Null <: Any](t: T = null): T = t
}
};
{
new $anon();
()
}
}
}
}