当您调用List 的构造函数时,它的参数会立即被评估(按值调用),因此对象3 将存储在List 中。
一般来说,scala 中的所有内容都是一个对象(撇开 JVM 表示细节不谈),所以您存储的是对 3 的不可变引用,而这又是不可变的。
另外,请注意 - 由于 referencial transparency(a 是对 3 的常量引用) - 存储对 a 的引用或其引用的对象没有任何区别,即它是“透明”。
因此,如果您想要一个不透明的引用,您可以稍后更改,您始终可以存储对可变对象的常量引用:
scala> class Foo(var foo: Int)
defined class Foo
scala> val x = new Foo(42)
x: Foo = Foo@3a654e77
scala> val a = List(x)
a: List[Foo] = List(Foo@3a654e77)
scala> a.head.foo
res25: Int = 42
scala> x.foo = 43
x.foo: Int = 43
scala> a.head.foo
res26: Int = 43
但那是邪恶的男孩!
根据性能问题,如果a 是一个大型不可变 集合,引用透明性允许在构造b 时重用现有集合a,而不是悲观地复制它。由于a 不能变异,所以根本不需要克隆。
您可以在 REPL 中轻松测试:
让我们创建一个不可变集合a
scala> val a = List(1, 2)
a: List[Int] = List(1, 2)
让我们使用a 来创建b
scala> val b = List(a, List(3, 4))
b: List[List[Int]] = List(List(1, 2), List(3, 4))
b 的第一个元素一模一样就是我们说的a
scala> b.head eq a
res18: Boolean = true
注意eq比较引用相等,所以上面不只是a的副本。进一步证明:
scala> List(1, 2) eq a
res19: Boolean = false