上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人
2.1.2 不可变性
正如前面的例子所示,函数式编程的一个关键特性是不可变性。如果某样东西不随时间变化,那么它就是不可变的。如果决定以函数式编程的方式编写代码,我们必须避免可变数据,使用纯函数对程序进行建模。
让我们来看一个例子。假设,我们使用字典在平面上定义了一个点和向量:
如果想计算用向量移动该点后所生成的点,我们可以用函数式编程的方式,用函数创建一个新点。示例如下:
这个函数是纯函数:给定相同的点和向量作为输入,得到的位移点总是相同,而且函数处理的数据没有任何改变,也包括函数参数。
运行这个函数,将之前定义的point和vector传入,结果如下:
与之相反,非函数式编程的解决方法可能需要使用如下函数来改变原来的点:
这个函数修改了作为参数输入的point,违反了函数式编程的关键规则。
请注意,函数名称中使用了in_place,这是一种常用的命名约定,它意味着原对象将被修改。我们将在全书中遵循这种命名约定。
现在,让我们看看使用displace_point_in_place函数会发生什么:
如你所见,函数没有返回任何东西,这是非纯函数的标志,因为函数发挥作用时,必然在某个地方改变了某些东西。在本例中,“某些东西”是点,其坐标已被更新。
函数式风格的一个重要优点是,通过恪守数据结构的不可变性,我们可以避免意料之外的副作用。当修改某个对象时,你可能并不知道代码中引用该对象的所有位置。如果有其他部分代码依赖于该对象的状态,就可能出现难以预料的副作用。因此,在对象发生改变之后,程序的行为可能与预期的不同。这类错误非常难发现,甚至可能需要数小时的调试。
在项目中尽量减少可变对象的数量,可以使其更可靠,更不容易出错。
现在让我们来看看一类特殊的函数——lambda函数,它在函数式编程中起着关键作用。