【问题标题】:Swapping elements of two Arrays in Scala with wildcard type在Scala中使用通配符类型交换两个数组的元素
【发布时间】:2013-03-21 08:10:32
【问题描述】:

我想做如下的事情:

class A[T] (_arr: Array[T]) { var arr = _arr }
class C {
  def foo[T <: A[_]](a: Array[T]){
    var ele1 = a(0)
    var ele2 = a(1)
    for(i <- 0 until ele1.arr.length) {
      val temp = ele1.arr(i)
      ele1.arr(i) = ele2.arr(i)
      ele2.arr(i) = temp
    }
  }
}

但我得到以下编译器错误:

<console>:15: error: type mismatch;
 found   : temp.type (with underlying type Any)
 required: _$1
             ele2.arr(i) = temp
                           ^

我不知道为什么 ele1.arr(i) = ele2.arr(i) 会工作和 ele2.arr(i) = 温度 不会。

编辑:根据雷克斯的建议,我将其更改为以下内容:

class A[T] (_arr: Array[T]) { var arr = _arr }
class C {
  def foo[T, B <: A[T]](b: Array[B]){
    var ele1 = b(0)
    var ele2 = b(1)
    for(i <- 0 until ele1.arr.length) {
      val temp = ele1.arr(i)
      ele1.arr(i) = ele2.arr(i)
      ele2.arr(i) = temp
    }
  }
}

现在编译好了。但是当我做一个测试用例时,如下:

object Test extends App {
  var p = Array.ofDim[A[Int]](2)
  var g1 = new A[Int](Array(1, 2, 3, 4, 5))
  var g2 = new A[Int](Array(6, 7, 8, 9, 10))
  p(0) = g1
  p(1) = g2

  (new C).foo(p)
  p.foreach{ x => println(x.arr.deep.mkString(",")) }
}

我收到以下编译器错误:

src/Test.scala:22: error: inferred type arguments [A[Int],Nothing] do not conform to method foo's type parameter bounds [B <: A[T],T]
  (new C).foo(p)
          ^
src/Test.scala:22: error: type mismatch;
 found   : Array[A[Int]]
 required: Array[B]
  (new C).foo(p)
              ^
two errors found

我知道我可以做 (new C).fooInt, A[Int],但我真的很想让编译器推断它。否则它有点违背了我所做的很多事情的目的。

【问题讨论】:

  • 据我所知,这两个数组的值的共同超类型返回为 Any,因为没有任何迹象表明这两个数组共享相同类型的值或具有共同的值祖先。例如,如果 ele1.arr 是一个数组或整数,而 ele2.arr 是一个 'People' 数组,它们如何能够在数组之间交换?

标签: arrays scala generics inheritance


【解决方案1】:

我不明白您为什么在这里使用通配符而不是参数化元素类型。您使编译器蒙蔽了双眼,并使其更难确保您在做一些明智的事情。特别是,它意识到由于数组是不变类型的,ele1.arr(i)ele2.arr(i) 是相同的类型,因此可以分配。但是当您分配给temp 时,它意识到它不知道该类型实际上可能是什么,因此它推断Any,然后当然不会重新放入数组中,因为它实际上不是 Any;它只是忘记了它应该是什么。

class C {
  def foo[T, B <: A[T]](b: Array[B]){
    var ele1 = b(0)
    var ele2 = b(1)
    for(i <- 0 until ele1.arr.length) {
      val temp = ele1.arr(i)
      ele1.arr(i) = ele2.arr(i)
      ele2.arr(i) = temp
    }
  }
}

允许编译器从头到尾知道类型,这让编译器很开心,也让你更安全。

【讨论】:

  • 感谢您的回复,这有所帮助,但我在上面进行了编辑以演示此实现的用例存在问题。非常感谢您提供的所有帮助,如果您知道一个好的资源或一个好的搜索词来阅读这些内容,请告诉我。
  • @MatthewSaltz - 我不知道如何解决这个问题;我希望类型推断器能够管理,但正如您所看到的那样,它显然不能。如果您不需要坚持使用子类型,它会起作用,但否则我不确定如何获得您想要的。
  • 非常感谢您的帮助。这很烦人,因为一个看似简单的问题变得非常复杂。我想创建一个类,它基本上是任何类型数组的容器。然后,我想创建另一个对扩展该类的任何对象进行操作的类。有什么我想念的吗?
  • @MatthewSaltz - 我以前从未遇到过这种情况。如果我有机会尝试一下,也许我会找到让编译器满意的方法,但我不知道我会不会有机会。
  • 非常感谢。创建一个更简洁的新问题会破坏论坛礼仪吗?类似于我在上一条评论中所说的内容?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-01-30
  • 2016-05-15
  • 1970-01-01
  • 1970-01-01
  • 2019-12-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多