首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Scala逆方差与协方差

Scala逆方差与协方差
EN

Stack Overflow用户
提问于 2013-10-29 20:23:59
回答 2查看 423关注 0票数 3

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

这是我的问题:

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

代码语言:javascript
复制
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的超级类型:

代码语言:javascript
复制
class CoVariance[+A]{
 def cast[B >: A](x : B) : A = {
  return x.asInstanceOf[A] 
 }
}

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

代码语言:javascript
复制
class ContraVariance[-A]{
 def cast[B, A <: B](x : B) : A = {
    return x.asInstanceOf[A]
 }
}

案例1:

代码语言:javascript
复制
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)

如果我把这个写出来

代码语言:javascript
复制
// Covariance[Point] -> 
// cast[B :> Point](x : B) : Point -> (fill in ColorPoint)
// Cast[ColorPoint :> Point] : Point 

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

下一个:

代码语言:javascript
复制
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)

如果我把这个写出来

代码语言:javascript
复制
// ContraVariance[Point] -> 
// cast[B, Point <: B](x : B) : Point -> (fill in ColorPoint)
// cast[ColorPoint, Point <: ColorPoint] : Point 

我也希望这是不正确的,但scala没有抱怨。我想说,Point不是ColorPoint的一个子类型。

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

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2013-10-29 20:36:37

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

您只能标记类型参数,如在协变或对变量位置。当您说Container[+A]时,您的意思是,如果Container[A]B的子类型,则可以将A的所有实例视为Container[B]的子类型。对于不可变的容器类来说,这是有意义的:您可以认为List[Person]List[Employee]的父类。请注意,这并没有说明转换规则--这些规则没有改变。

反变体是相似的,但恰恰相反。如果有Writer[-A],则表示Writer[A]Writer[B]的子类型,如果BA的子类型。您也可以看到这是如何直观地理解的:如果您有一个Writer[Person],它可以将一个人写进某个目的地,而Writer[Employee]是一个只能写员工的作者,那么Writer[Employee]作为Writer[Person]的父母是有意义的,因为编写Person是编写完整的Employee的一个子任务,尽管类型本身正好相反。

票数 5
EN

Stack Overflow用户

发布于 2013-10-29 20:38:05

  1. asInstanceOf[T]忽略了打字机。所以你甚至可以有以下演员阵容: def castB:B = a.asInstanceOfB 用于任何AB。 因此,就您的情况而言,Scala不会抱怨。
  2. 如果我正确理解,您希望只有在类型有适当的关系(父-子)时才使用cast方法。我认为,您不必在类声明中使用+/-。只有两种不同的类型: 隐式类CastToParentA { def castB >:A:B = a.asInstanceOfB }隐式类CastToChildA { def castB <:A:B = a.asInstanceOfB } 这允许您进行所需的转换。 特征A特征B扩展A性状C val a:A =新B {} val = a.castB //parent to child val a1 = b.castA //child to parent。val = a.castC //不编译
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/19668353

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档