【问题标题】:Error: Covariant type A occurs in contravariant position错误:协变类型 A 出现在逆变位置
【发布时间】:2011-03-09 04:53:11
【问题描述】:

我试图编写一个不可变的Matrix[A] 类。我希望类在 A 上是协变的,但是当我将 + 放在 A 前面时,编译器开始抱怨类中的一些操作。

以下是我的 Matrix 类的相关子集(实际类比以下子集大 5 倍):

class Matrix[+A] private(val contents: Vector[Vector[A]])(implicit numericEv: Numeric[A])
    extends ((Int, Int) => A) with Proxy {

  import numericEv._
  import Prelude._

  // delegate `equals` and `hashCode` implementations to `contents`
  override def self = contents

  val nRows: Int = contents.length

  val nColumns: Int = contents(0).length.ensuring { len =>
    contents.forall(_.length == len)        
  }

  def dimensions = (nRows, nColumns)

  def isSquare = nRows == nColumns

  def hasSameOrderAs[B : Numeric](that: Matrix[B]) = this.dimensions == that.dimensions

  def isComformableWith[B : Numeric](that: Matrix[B]) = this.nColumns == that.nRows

  private def assertSameOrder[B : Numeric](that: Matrix[B]) {
    assert(this.hasSameOrderAs(that), "Matrices differ in dimensions.")
  }

  private def assertIsSquare() {
    assert(this.isSquare, "Not a square matrix.")
  }      

  def zipWith[B : Numeric, C : Numeric](that: Matrix[B])(f: (A, B) => C): Matrix[C] = {
    assertSameOrder(that)
    val zippedContents = (contents, that.contents).zipped.map((v1, v2) => (v1, v2).zipped.map(f))
    Matrix(zippedContents)
  }

  def map[B : Numeric](f: A => B): Matrix[B] = {
    Matrix(contents.map(_.map(f)))
  }

  def transpose: Matrix[A] = {
    assertIsSquare()
    Matrix(contents.transpose)
  }

  def +(that: Matrix[A]): Matrix[A] = this.zipWith(that)(_ + _)

  def -(that: Matrix[A]): Matrix[A] = this.zipWith(that)(_ - _)

  def *(scalar: A): Matrix[A] = this.map(_ * scalar)

  def *(that: Matrix[A]): Matrix[A] = {
    assert(this.isComformableWith(that))
    Matrix.tabulate(this.nRows, that.nColumns) { (r, c) =>
      (this(r), that.transpose(c)).zipped.map(_ * _).sum
    }
  }
}

object Matrix {
  def apply[A : Numeric](rows: Vector[A]*): Matrix[A] = Matrix(Vector(rows: _*))

  def apply[A : Numeric](contents: Vector[Vector[A]]): Matrix[A] = new Matrix(contents)

  def tabulate[A : Numeric](nRows: Int, nColumns: Int)(f: (Int, Int) => A): Matrix[A] = {
    Matrix(Vector.tabulate(nRows, nColumns)(f))
  }
}

编译器对类中的最后四个操作显示错误“协变类型 A 出现在逆变位置”。我无法理解这些错误的原因,以及如何摆脱它。请解释这些错误背后的原因并提出解决方法。谢谢。

【问题讨论】:

标签: scala covariance contravariance


【解决方案1】:

这些错误的原因是在你做的时候声明它不是类型安全的。例如,可以这样做,否则:

class A(val x: Int)
class B(x: Int, val y: Int) extends A(x)

object NA extends Numeric[A] {
    def toDouble(x: A): Double = x.x.toDouble
    def toFloat(x: A): Float = x.x.toFloat
    def toLong(x: A): Long = x.x.toLong
    def toInt(x: A): Int = x.x
    def fromInt(x: Int): A = new A(x)
    def negate(x: A): A = new A(-x.x)
    def times(x: A,y: A): A = new A(x.x * y.x)
    def minus(x: A,y: A): A = new A(x.x - y.x)
    def plus(x: A,y: A): A = new A(x.x + y.x)
    def compare(x: A,y: A): Int = implicitly[Numeric[Int]].compare(x.x, y.x)
}

object NB extends Numeric[B] {
    def toDouble(x: B): Double = x.x.toDouble / x.y.toDouble
    def toFloat(x: B): Float = x.x.toFloat / x.y.toFloat
    def toLong(x: B): Long = (x.x / x.y).toLong
    def toInt(x: B): Int = x.x / x.y
    def fromInt(x: Int): B = new B(x, 1)
    def negate(x: B): B = new B(-x.x, x.y)
    def times(x: B,y: B): B = new B(x.x * y.x, x.y * y.y)
    def minus(x: B,y: B): B = new B(x.x * y.y - y.x * x.y, x.y * y.y)
    def plus(x: B,y: B): B = new B(x.x * y.y + y.x * x.y, x.y * y.y)
    def compare(x: B,y: B): Int = implicitly[Numeric[Int]].compare(x.x * x.y, y.x * y.y)
}

val mb = Matrix.tabulate(10, 10)((x, y) => new B(x, y))
def f(m: Matrix[A]) = {
  val ma = Matrix.tabulate(m.nRows, m.nColumns)((x, y) => 1)
  m + ma
}
f(mb)

注意m + ma 不能工作,因为m.+ 需要一个B 类型的对象。但是,如果 Scala 允许您按照自己的方式编写它,那将是允许的。

避免这个问题的常用方法是这样写方法:

def +[B >: A](that: Matrix[B])(implicit num: Numeric[B]): Matrix[B] = this.zipWith(that)(B.plus)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-01-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-29
    • 1970-01-01
    • 2015-04-11
    相关资源
    最近更新 更多