繁体   English   中英

Scala集合如何在相反位置使用某些变体类型?

[英]How do Scala collections use some variant types in contravariant position?

考虑一个Scala GenTraversible例如List或一个特征(例如GenTraversibleGenTraversibleLike 所有这些都用类型A定义,以便它是变量(例如List[+A] )。

这些类型/特征具有某些方法,例如contains(elem: A)filter(pred: A => Boolean)

我不明白为什么允许这样做-即使类别/特征声明为+A (变体),似乎A型也出现在变数位置。

对于containsfilter A处于协变位置。

contains的签名实际上是:

def contains[A1 >: A](elem: A1): Boolean

当在下类型边界的右侧使用类型变量时,它处于协变位置。

使用filter ,参数的类型为A => Boolean ,即Function1[A, Boolean] Function1的第一个参数是互变量的,而Function1本身作为要filter的参数处于互变的位置。 两个逆方差组合在一起构成协方差。

解决这个问题的一种方法是给List[X]成像,其中X <: Y 如果将此List[X]强制转换为List[Y] ,这些方法是否仍然是类型安全的? 现在contains要求A1Y的超类型,这实际上是更严格的要求。 filter现在需要一个函数Y => Boolean ,这也是一个更严格的要求,因为传入的函数必须能够处理任何Y ,而不仅仅是X实例。 另一方面,将List[Y]强制转换为List[Y] List[X]将不是类型安全的。 如果X也是Z子类型,但Y没有,并且Z被用于contains A1 ,那么将违反类型绑定,因为Z >: Y不是真的。 对于filter,传递的函数将是X => Boolean ,并且不能安全地传递List包含的Y的实例。 因此,我们可以得出结论,在这些方法中, A确实处于协变而非协变的位置。

允许这样做是因为对于协变类型,采用参数的方法的LOWER BOUND可以为T。请考虑以下示例:

trait myList[+T] {

  def prepend(elem: T): List[T] = new Cons(elem, this)
}

这将不起作用,因为您不能将协变类型作为参数-您将获得编译时错误。 另一方面,您可以将方法参数限制为T的下限-参数可以是T或T的超类型,而不是子类型,例如

trait myList[+T] {

  def prepend[S >: T](elem: S): List[S] = new Cons(elem, this)
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM