最小工作示例(Scala 2.9.2):
object Main extends App {
class A {
var a=0
}
val b = Array.fill(2)(new A)
b(1).a = 9
println(b(0).a) //prints 0
println(b(1).a) //prints 9
val a = new A
val c = Array.fill(2)(a)
c(1).a = 9
println(c(0).a) //prints 9
println(c(1).a) //prints 9
}
一个相关的问题是"导入的 Java 类是否相同?如果我需要使用作为参数传递的实例的副本填充函数中的数组,我该如何解决方法?[关于相同的副本,值得我查看简单的克隆库。
只需根据答案将解决方法添加到函数调用中:
class A {
var a=0
}
def f(a: => A) { // "=>" added
val b = Array.fill(2)(a)
b(1).a=9
println(b(0).a) //prints 0
println(b(1).a) //prints 9
}
f(new A)
另一种方法是声明一个函数,而不是一个值def a = new A
:
object Main extends App {
class A {
var a=0
}
val b = Array.fill(2)(new A)
b(1).a = 9
println(b(0).a) //prints 0
println(b(1).a) //prints 9
def a = new A
val c = Array.fill(2)(a)
c(1).a = 9
println(c(0).a) //prints 0
println(c(1).a) //prints 9
}
fill
方法的第二个参数定义为"按名称调用"。 这意味着将针对数组中的每个单元格重新评估传入的块。 在定义中看到elem
的类型是=> T
,而不仅仅是T
:
def fill[T: ClassManifest](n: Int)(elem: => T): Array[T]
因此,在您的第一个版本中,将重新评估每个单元格的块new A
,这意味着每个单元格都会获得一个新的A
对象。 在第二个版本中,new A
只调用一次,并且该对象被放置在每个单元格中。
如果你在 REPL 上运行,你实际上可以看到这一点:
scala> val b = Array.fill(2)(new A)
b: Array[A] = Array(A@2049bed2, A@498edd8d) // two different objects
scala> val c = Array.fill(2)(a)
c: Array[A] = Array(A@31e0c0b6, A@31e0c0b6) // the same object repeated
查看填充签名
def fill[T: ClassManifest](n: Int)(elem: => T)
因此,它获得一个按名称调用的参数,这意味着每次处理数组中的单元格时都会执行new A
。
一个用 A 的单个实例填充数组,另一个用 A 的新实例填充数组。