Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/backbone.js/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scala协方差误差_Scala_Covariance - Fatal编程技术网

Scala协方差误差

Scala协方差误差,scala,covariance,Scala,Covariance,我试图编译以下代码,但最后一行没有编译: class SuperContainer ( val shapeSets: Set[MyContainer[Shape]] = Set.empty[MyContainer[Shape]]) { def addAct(el: MyContainer[Shape]) = { new SuperContainer(shapeSets + el) } } class MyContainer[A](val ls: Set[A] = Set

我试图编译以下代码,但最后一行没有编译:

class SuperContainer (
  val shapeSets: Set[MyContainer[Shape]] = Set.empty[MyContainer[Shape]]) {

  def addAct(el: MyContainer[Shape]) = {
    new SuperContainer(shapeSets + el)
  }

}

class MyContainer[A](val ls: Set[A] = Set.empty[A]) {
  def addElement(el: A) = {
    new MyContainer(ls + el)
  }
}  


abstract class Shape

case class Circle(radius: Int) extends Shape {
  override def toString = "Circle(" + radius + ")"
}
case class Square(s: Int) extends Shape {
  override def toString = "Square(" + s + ")"
}


object MyContainer {
  def main(args: Array[String]) {
    //Circle Container
    val myc1 = new MyContainer[Circle]()
    val myc11 = myc1.addElement(new Circle(6))

    //Square Container
    val myc2 = new MyContainer[Square]()
    val myc21 = myc2.addElement(new Square(6))


    val scont = new SuperContainer
    scont.addAct(myc11) //does not compile
  }
}

Scala编译器建议我在MyContainer类定义中使用+A,但这样做会出现其他编译错误。是我做错了什么,还是这只是Scala的限制?有什么方法可以克服这个问题吗?

为了实现您想要的,MyContainer必须是协变的:

class MyContainer[+A](val ls: Set[A] = Set.empty[A]) // ...
现在,您对
addElement
的定义将导致错误,因为
A
出现在逆变位置(在本例中作为函数参数)。您必须修改您的签名,如下所示:

def addElement[B >: A](el: B): MyContainer[B]
如果你想一想,这是有道理的:如果你有一个
容器[圆]
(由于协方差,它可以被视为
容器[形状]
),并且你添加了一个
形状
,那么你在末尾有一个
容器[形状]
,而不是
容器[圆]

addElement
的实现不会改变

此外,由于
设置[A]
,因此不能使
设置[A]
在类外可用(即必须删除
val
)。如果要访问元素,则必须添加其他方法来查询集合

class MyContainer[+A](ls: Set[A] = Set.empty[A]) // ...
更新

这是为了更清楚地解释为什么
Set[A]
不能成为
MyContainer[+A]
的公共API的一部分。假设我们有:

class A
class B extends A
想象一下:

val x: MyContainer[A] = new MyContainer[B]
我们可以这样做,因为协方差。但是,如果我们现在可以打电话:

val s = x.ls // get internal set

我们希望
s
属于
Set[A]
类型。但是,
x
的内部
集合
是一个
集合[B]
集合[a]
。因此,键入的内容不正确。

为了实现您想要的内容,
MyContainer
必须是协变的:

class MyContainer[+A](val ls: Set[A] = Set.empty[A]) // ...
现在,您对
addElement
的定义将导致错误,因为
A
出现在逆变位置(在本例中作为函数参数)。您必须修改您的签名,如下所示:

def addElement[B >: A](el: B): MyContainer[B]
如果你想一想,这是有道理的:如果你有一个
容器[圆]
(由于协方差,它可以被视为
容器[形状]
),并且你添加了一个
形状
,那么你在末尾有一个
容器[形状]
,而不是
容器[圆]

addElement
的实现不会改变

此外,由于
设置[A]
,因此不能使
设置[A]
在类外可用(即必须删除
val
)。如果要访问元素,则必须添加其他方法来查询集合

class MyContainer[+A](ls: Set[A] = Set.empty[A]) // ...
更新

这是为了更清楚地解释为什么
Set[A]
不能成为
MyContainer[+A]
的公共API的一部分。假设我们有:

class A
class B extends A
想象一下:

val x: MyContainer[A] = new MyContainer[B]
我们可以这样做,因为协方差。但是,如果我们现在可以打电话:

val s = x.ls // get internal set

我们希望
s
属于
Set[A]
类型。但是,
x
的内部
集合
是一个
集合[B]
集合[a]
。因此,键入的内容不正确。

为了实现您想要的内容,
MyContainer
必须是协变的:

class MyContainer[+A](val ls: Set[A] = Set.empty[A]) // ...
现在,您对
addElement
的定义将导致错误,因为
A
出现在逆变位置(在本例中作为函数参数)。您必须修改您的签名,如下所示:

def addElement[B >: A](el: B): MyContainer[B]
如果你想一想,这是有道理的:如果你有一个
容器[圆]
(由于协方差,它可以被视为
容器[形状]
),并且你添加了一个
形状
,那么你在末尾有一个
容器[形状]
,而不是
容器[圆]

addElement
的实现不会改变

此外,由于
设置[A]
,因此不能使
设置[A]
在类外可用(即必须删除
val
)。如果要访问元素,则必须添加其他方法来查询集合

class MyContainer[+A](ls: Set[A] = Set.empty[A]) // ...
更新

这是为了更清楚地解释为什么
Set[A]
不能成为
MyContainer[+A]
的公共API的一部分。假设我们有:

class A
class B extends A
想象一下:

val x: MyContainer[A] = new MyContainer[B]
我们可以这样做,因为协方差。但是,如果我们现在可以打电话:

val s = x.ls // get internal set

我们希望
s
属于
Set[A]
类型。但是,
x
的内部
集合
是一个
集合[B]
集合[a]
。因此,键入的内容不正确。

为了实现您想要的内容,
MyContainer
必须是协变的:

class MyContainer[+A](val ls: Set[A] = Set.empty[A]) // ...
现在,您对
addElement
的定义将导致错误,因为
A
出现在逆变位置(在本例中作为函数参数)。您必须修改您的签名,如下所示:

def addElement[B >: A](el: B): MyContainer[B]
如果你想一想,这是有道理的:如果你有一个
容器[圆]
(由于协方差,它可以被视为
容器[形状]
),并且你添加了一个
形状
,那么你在末尾有一个
容器[形状]
,而不是
容器[圆]

addElement
的实现不会改变

此外,由于
设置[A]
,因此不能使
设置[A]
在类外可用(即必须删除
val
)。如果要访问元素,则必须添加其他方法来查询集合

class MyContainer[+A](ls: Set[A] = Set.empty[A]) // ...
更新

这是为了更清楚地解释为什么
Set[A]
不能成为
MyContainer[+A]
的公共API的一部分。假设我们有:

class A
class B extends A
想象一下:

val x: MyContainer[A] = new MyContainer[B]
我们可以这样做,因为协方差。但是,如果我们现在可以打电话:

val s = x.ls // get internal set

我们希望
s
属于
Set[A]
类型。但是,
x
的内部
集合
是一个
集合[B]
集合[a]
。因此,键入的内容不正确。

我不明白您想要实现什么:您的add*函数不返回任何内容(您的