是这个的答案:
对象的实例化使用“val”而不是“var”。
正在创建的对象的每个成员变量也是“val”而不是“var”。这是为了防止用户在设置后更新对象值。
如果该对象的用户无法更改该对象,则该对象是不可变的。这意味着它必须没有公共方法来重新分配其任何成员变量或改变这些变量引用的任何对象。如果所有对象的成员都是val
s 这确保前者(即它们不能被重新分配),但不是后者(即如果这些变量引用的对象本身是可变的,它们仍然可以通过调用它们的变异方法来变异即使它们仅由val
s 引用)。
另请注意,即使成员被声明为var
s,如果对象的方法都没有真正重新分配变量(或在它们上调用变异方法),则对象仍然可以是不可变的 - 当然,假设它们是私有的。
因此,对于一个不可变的对象来说,只有val
成员既不是必要的,也不是充分的。无论对象是由 aval
还是 a var
(或两者)引用,在这件事上都没有区别。
@sepp2k 很好且正确地解释了对象在技术上不可变的标准。他的回答中缺少的一个微妙点是,并非所有成员变量都对应于外部可见状态。成员也可以是例如缓存的内部值,用于存储一些本地的、难以计算的数据,这些数据从外部不直接可见(因此private[this]
在 Scala 中是合格的)。对象可以具有这样的var
成员,例如存储计算的散列值。它甚至可以通过公共 getter 访问——只要访问器的行为是纯函数式的,即它总是为同一个对象的每次调用产生相同的值(除了在重用内部缓存值时它返回更快)。
Scala 编译器意识到了这一区别,因此它可以帮助人们正确实现不可变类,即使在内部使用可变状态时也是如此。当泛型类型变化发挥作用时,这一点很重要。即,编译器允许泛型类型参数是协变的,即使该类包含此类型的可重新分配字段 - 只要这些字段是private[this]
,确保不能引用具有静态比该类型更弱的类型的包含对象对象是用定义的(这将是导致类型错误的方差的先决条件)。
这在Programming in Scala的第 19.7 节中通过代码示例进行了更详细的解释。