将 `T[_ <: U]` 转换为 `T[U]`
Cast `T[_ <: U]` to `T[U]`
我有一个 java 类型 public interface T<U>
,它是不可变的并且逻辑上是协变的(只读),但在 scala 中是不变的,因为它是在 Java.[=13 中定义的=]
我可以安全地将 T[_ <: U]
转换为 T[U]
吗?如果有怎么办?
如果 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 类型系统是合理的情况下,转换是合理的。
immutable and logically covariant (read-only)
只读和不可变并不意味着它是 "logically covariant"!例如。 Consumer<A>
(Scala 中的A => Unit
)是只读和不可变的,但它应该是逆变的。所以答案是,这取决于。
it's a collection/iterator-ish type with methods like public U next() so still covariant
为了协变,它不应该有检查类型 U
值的方法(除了使用 hashCode
和 equals
),所以例如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]]
我有一个 java 类型 public interface T<U>
,它是不可变的并且逻辑上是协变的(只读),但在 scala 中是不变的,因为它是在 Java.[=13 中定义的=]
我可以安全地将 T[_ <: U]
转换为 T[U]
吗?如果有怎么办?
如果 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 类型系统是合理的情况下,转换是合理的。
immutable and logically covariant (read-only)
只读和不可变并不意味着它是 "logically covariant"!例如。 Consumer<A>
(Scala 中的A => Unit
)是只读和不可变的,但它应该是逆变的。所以答案是,这取决于。
it's a collection/iterator-ish type with methods like public U next() so still covariant
为了协变,它不应该有检查类型 U
值的方法(除了使用 hashCode
和 equals
),所以例如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]]