Scala对可变性和数组/列表感到困惑

时间:2011-08-10 10:47:24

标签: scala

给出一个简单的Matrix实现

class Matrix(val matrix: Array[Array[Double]]) {
...
  def add(scalar:Double) { matrix.map(_.map( _ + scalar )) }
  def set(row:Int,col:Int,value:Double) { matrix(row)(col) = value }
...
}

据我所知,Mutability意味着我无法重新分配矩阵,但我可以在其中设置新值。正如set()工作所证明的那样。

现在添加的实现已被打破,但我仍然坚持如何最好地实现它。我对使用transform

充满希望
def add(scalar:Double) { matrix.transform(_.transform( _ + scalar )) }  
// type mismatch; found : ...WrappedArray[Double] required: Array[Double]

但是我无法编译它。那么有一种方法可以让上面的例子起作用吗?

请随意解决我的逻辑中有关列表/数组可变性的任何缺陷:P

2 个答案:

答案 0 :(得分:4)

实际上,您无法重新分配给matrix,因为它是val(引用是不可变的)。可以更改Array的实例,因为Array的接口允许,这使得它成为可变类。

因此不允许matrix =matrix.map的调用有效,它会创建一个新数组,保持matrix不变。由于第二个matrix,它还会更改map内的子数组。不是你想要的。最后,结果无法分配给matrix,因为不允许分配给matrix

transform确实是要走的路。但是您想要更改的数组是matrix)中的数组,而不是matrix本身,它们仍应包含相同(但已更改)的行。正确的电话是

matrix.foreach(_.transform(_ + scalar)

然而,你的版本应该有效。 transform返回呼叫的目标。关键是你可以链接来电,a.transform(...).doSomethingElse().andAgain()(这里你不需要)。所以你的matrix.transform应该是一个变换(身份) - 副作用是这个特定的身份会改变行的内容,这本来就没问题。

问题是转换实际上不是Array的方法(数组在JVM中并且没有这样的方法)。它来自隐式转换。从Array有两个值得注意的隐式转换,一个到ArrayOps,另一个到WrappedArray(文章Fighting Bit Rot with Types中的详细信息,到最后)。方法transform位于WrappedArray。它的返回类型必须是WrappedArray,因为变换在类型层次结构中定义得很好,并强制结果为this。这意味着transform不太有趣的结果不应该用于数组。所以你必须选择foreach

答案 1 :(得分:1)

您需要使用matrix.map(_.map( _ + scalar ))的返回值执行某些操作。根据此值创建一个新矩阵并将其返回:

def add(scalar:Double) = { new Matrix(matrix.map(_.map( _ + scalar ))) }

您无法再次分配给matrix,因为这是val的属性(无法分配新值)。
用法是:

val matrix = new Matrix(Array(Array(1,2)))
val newMatrix = matrix.add(5)