将`T [_&lt ;: U]`转换为`T [U]`

时间:2017-03-20 14:38:16

标签: scala covariance

我有一个java类型public interface T<U>,它是不可变的和逻辑协变的(只读),但在scala中是不变的,因为它是用Java定义的。

我可以安全地将T[_ <: U]投射到T[U]吗?如果是这样的话?

2 个答案:

答案 0 :(得分:1)

如果T是协变的(或者没有注释,但是应该有),那么是的:

scala> trait T[+X]
defined trait T

scala> trait U
defined trait U

scala> val a: T[_ <: U] = null
a: T[_ <: U] = null

scala> val b: T[U] = a
b: T[U] = null

这足以表明在Scala类型系统声音合理的情况下,演员阵容会发出声音。

答案 1 :(得分:1)

  

不可变和逻辑协变(只读)

只读和不可变并不意味着它是“逻辑协变”!例如。 Consumer<A>(Scala中的A => Unit)是只读且不可变的,但它应该是逆变的。所以答案是,这取决于。

  

它是一个集合/ iterator-ish类型,其方法如public U next()所以仍然是协变的

为了协变,它应该没有方法检查U类型的值(除了使用hashCodeequals),例如, List.add没问题(对于不可变列表),HashSet.contains没问题,TreeSet.contains没有。

假设这样,演员是安全的。当然,Scala的编译器无法知道它,所以你仍然需要asInstanceOf

val t1: T[SomeSubtypeOfU] = ...
val t2 = t1.asInstanceOf[T[U]]

您可以将其隐藏在隐式转化后面:

implicit def tIsCovariant[A](x: T[_ <: A]): T[A] = x.asInstanceOf[T[A]]