最近刚学scala,对val var可变与不可变感觉很迷惑,然后看了一些博客发现
因为Scala的数据类型和数据结构全部都是用类来封装的,所以Scala中的可变与不可变都是针对类的实例对象的,
val不可变指的是不能改变初始化时指向的类的实例对象,但是这个对象自己的值可以变
var可变指的是可以改变初始化时指向的类的实例对象,而且这个对象的值或者新指向的对象的值可以变
用一个很多博客都举的例子:
class A(n: Int) {
var value = n
}
class B(n: Int) {
val value = new A(n)
}
object Test {
def main(args: Array[String]) {
val x = new B(5)
x = new B(6) // Doesn't work, because I can't replace the object created on the line above with this new one.
x.value = new A(6) // Doesn't work, because I can't replace the object assigned to B.value for a new one.
x.value.value = 6 // Works, because A.value can receive a new object.
}
}
可以看到 x 与x.value都不能被重新赋值,以为他们都被val声明,一旦指向一个对象就不能再被指向其他的对象了, 但是这个对象自身的状态是会改变的,例如x.value.value就能被重新赋值了。
而且要注意在碰到可变与不可变数据结构,对val变量的影响
对于可变的数据结构,进行操作直接改变原数据结构对象的值,所以val指向的数据结构的对象不变,所以可以操作成功
但是对于不可变的数据结构,进行操作改变的不是原数据结构对象的值,而是返回一个新的数据结构对象,这时需要改变val指向的数据结构,所以报错
例如
val numbers= ArrayBuffer(1,2,3)
numbers+=5//success
val numbers=Set(1,2,3)
numbers+=5//error
val不是不可变的吗,怎么能numbers+=5?
val numbers指向了一个可变的数据结构 数组缓冲ArrayBuffer ,numbers是可以进行
numbers+=5操作的, 这是因为所指的这个对象是有自己的状态的,比如这里的对象是ArrayBuffer类型,这个的对象的状态是可以改变的,但是你不能val numbers =ArrayBuffer(1,2) 了,被val声明的numbers只能指向这个对象,但是这个对象自身的状态是可以改变的
Set是一个不可变对象,numbers+=的意义是什么呢?它返回一个新的对象Set(1,2,3,5) 原来的Set(1,2,3) 你无法改变,因为他是一个不可变的对象,numbers需要指向这个新的Set对象,所以失败. 可变对象数组缓冲的方法“+=”返回的是修改后的原来的集合,而不可变对象Set的“+=”返回的是一个新的集合