问题描述
假设你有一个变量:
var x = [1,2]
如果它是一个可变对象,你可以这样做:
x.append(3)
x
>> [1,2,3]
但如果它是不可变的,并且您想更改 x 的值,则您必须有效地执行以下操作:
// init x
var x = [1,2]
// add a 3 to x
x = [1,3]
x
>> [1,3]
可变性和仅仅改变变量有什么区别?
我最好的猜测是,当您执行 append(3)
时,它正在修改对内存中同一变量的引用,但是当您执行 x = [1,3]
时,您可能会声明一个新变量 x,引用中的一个新块内存,并释放 x=[1,2]
占用的旧块。
似乎不可变的变量不应该改变。但是很多时候我们希望不可变的变量发生变化。例如,在 React 中,状态变量被认为是不可变的。但是拥有状态的意义在于变量可以改变。因此,要更改它们的值,您需要通过这些非常迂回的方式,例如调用 setState()
,如果您想执行诸如将元素添加到列表之类的操作,则为其提供回调函数。
解决方法
有变量,也有值。变量就像我们用来指代值的名称或地址。可变性适用于值,而不是变量。
可变值可以就地更改,而无需创建新值。例如,如果我创建一个整数值并将其赋值为 1,那么我可以增加该值而无需为新整数分配空间;该值在原地增加。对该值的任何引用都会立即看到更改,因为它们指的是现在已更改或变异的值。
不可变值不能就地更改。假设字符串在我们的语言中是不可变的。如果我创建一个字符串并将其初始化为值“hello world”,则不可能在不为新字符串创建空间的情况下更改该值。如果我想将值更改为“再见世界”,我必须使用新分配的内存创建一个新的字符串值。任何引用原始值的变量将继续这样做,除非它们被更新为引用新值。
常量是一个类似的概念,适用于变量,与是否允许变量引用的事物发生变化有关。这与原始类型有点混乱;实际上,const int 变量应该是可递增的,因为递增 int 不会改变所引用的内存,只是该内存中的内容。但是,例如,常量/只读列表通常可以毫无问题地添加和删除,因此(变量引用的)常量性和(值的)不变性之间的区别在那里保存得更好一些。