3

我正在玩 scala 的类型系统,发现了一个奇怪的案例。我有充分的理由相信,我不了解协变和协变。

这是我的问题案例:

我有两个类,Point 和 ColorPoint,它是 Point 的子类。

class Point(val x : Int, val y : Int)
class ColorPoint(x : Int, y : Int, val red : Int, val green : Int, val blue : Int) extends Point(x,y) 

这个类将 B 转换为 A,而 B 应该是 A 的超类型:

class CoVariance[+A]{
 def cast[B >: A](x : B) : A = {
  return x.asInstanceOf[A] 
 }
}

这个类将 B 转换为 A,而 B 应该是 A 的超类型:

class ContraVariance[-A]{
 def cast[B, A <: B](x : B) : A = {
    return x.asInstanceOf[A]
 }
}

情况1:

val co = new CoVariance[Point]
val color_point = new ColorPoint(1,2,3,4,5)
val point_co = co.cast(color_point) 
println(point_co.x)

如果我把这个写出来:

// Covariance[Point] -> 
// cast[B :> Point](x : B) : Point -> (fill in ColorPoint)
// Cast[ColorPoint :> Point] : Point 

我认为这是不正确的,因为 ColorPoint 不是 Point 的超类型,但 scala 不会抱怨。

下一个:

val contra = new ContraVariance[Point]
val color_point_contra = new ColorPoint(1,2,3,4,5)
val point_contra = contra.cast(color_point_contra) 
println(point_contra.x)

如果我把这个写出来:

// ContraVariance[Point] -> 
// cast[B, Point <: B](x : B) : Point -> (fill in ColorPoint)
// cast[ColorPoint, Point <: ColorPoint] : Point 

我也认为这是不正确的,但 scala 不会抱怨。我会说 Point 不是 ColorPoint 的子类型。

我的推理是正确的还是我遗漏了什么?

4

2 回答 2

5

我认为您误解了协变和逆变位置是什么。这并不意味着您可以在某些类型之间进行强制转换,它只是建立了参数化类型之间的继承关系。

您只能将类型参数标记为协变或逆变位置。当您说 时Container[+A],您是在说您可以将 的所有实例Container[A]视为Container[B]ifA的子类型的子类型B。这对于不可变容器类是有意义的:您可以将 aList[Person]视为List[Employee]. 请注意,这并没有说明强制转换规则——那些没有改变。

逆变是相似的,但相反。如果你有Writer[-A],它说Writer[A]是一个子类型Writer[B]ifB是一个子类型A。你也可以看到这在直觉上是如何有意义的:如果你有一个Writer[Person]可以将 Person 写入某个目的地的东西,而你有Writer[Employee]一个只能写Employees的作家,那么Writer[Employee]作为父母是有意义的,Writer[Person]因为写 aPerson是编写一个 full 的子任务Employee,即使它与类型本身相反。

于 2013-10-29T20:36:37.177 回答
2
  1. asInstanceOf[T]忽略类型检查。所以你甚至可能有以下演员:

    def cast[B](a:A):B = a.asInstanceOf[B]
    

    对于任何AB

    因此,在您的情况下,Scala 不会抱怨。

  2. cast如果我理解正确,那么只有在类型处于适当关系(父子关系)时才需要方法。我认为,你不需要+/-在课堂上声明。只有两种不同的演员表:

    implicit class CastToParent[A](a:A) {
      def cast[B >: A]:B = a.asInstanceOf[B]
    }
    
    
    implicit class CastToChild[A](a:A) {
      def cast[B <: A]:B = a.asInstanceOf[B]
    }
    

    这使您可以进行所需的转换。

    trait A
    trait B extends A
    trait C
    val a:A = new B {}
    val b   = a.cast[B] //parent to child
    val a1  = b.cast[A] //child to parent.
    val c   = a.cast[C] // don't compile
    
于 2013-10-29T20:38:05.947 回答