程序中的命名与作用域
最近在读《代码之髓》,里面讲解了很多编程语言中的concepts是为何产生的。本篇笔记主要参考了书中的第7章:名字与作用域。
命名
计算机在执行程序时是根据内存地址中的信息来执行的,其无需得知每个变量的名字是什么。因此早期的编程中是没有命名这一概念的。后来为了方便人在编程时对变量所代表的含义和类型进行记忆,才开始给变量和函数进行取名。例如,相比于"经度:108.654519、纬度:34.255314"来说,中国西部科技创新港更容易理解和记忆,又比如相比"8.7.198.46"来说,"某个不存在的网站"这种描述更令人印象深刻。
那么计算机是如何将名字和变量及函数对应起来的呢,答案是使用对照表。这类似与我们在图书馆里找一本书,通过在数据库中检索,便可以将书名转换为分类编号,再通过分类编号既可以找到想要借阅的书在哪里。以创新港的图书馆为例:
1 | 《代码之髓》=>TP312/159,《古今数学思想第一册》=>O11/510-1/C.1 |
有了这样的对照表,计算机在处理"找到《代码之髓》"这个命令时,便可以转换成"找到编号为TP312/159的图书"来进行执行。
以python为例:
1 | x = 'python' |
在上述程序中,计算机建立了如下的对照表:
graph LR x[x]-->a[2256008235312] y[y]-->b[2256008254512] z[z]-->a
在上面的对照表中,变量x和变量z指向了同一个内存地址,因此,当变量z发生改变时,变量x也会相应的发生改变。只不过python中str不可变罢了
命名冲突
在早期的程序设计中,对照表是整个程序所共有的。这就会产生一些问题,例如下面这段C++代码:
1 |
|
这个循环理应运行10次结束,然而,如果在函数print
中对i
进行了操作呢:
1 | void print(){ |
由于变量i
在函数内部和函数外部中都被使用了,使得其无法在预期的10次for
循环之后直接结束。将会无限次循环。
如何避免这种命名冲突呢,一种方法是取更长的名字,在名字中说明这个变量是用于哪里的。例如i_in_print
和i_in_main
,在多人合作开发时采用变量名申请制来进行管理。
然另一种方法就是引入作用域。下文将主要围绕作用域展开。
作用域
作用域是指名字的有效范围,为了不让print
函数中对i
的操作影响到外部,那么在函数执行之前将其值存储起来,在函数执行结束之后再取出来便可以解决这个问题。这种机制被称为动态作用域
动态作用域
以Perl
语言为例,在函数执行入口保存变量值,在结束时重新写回变量
1 | sub shori{ |
然而,这样的作法存在一个问题,那就是函数在嵌套调用时,对变量的修改会作用到被调用的函数中,以下面这两个函数为例:
1 | $x = "global" |
调用函数yobu
时,变量x
被改写为yobu
,在函数运行结束重新写回之前,调用yobarebu
函数时显示使用的变量x
的值为yobu
。这说明函数yobu
中对变量的更改对于在其中调用的函数运行有影响。
产生这种现象的原因时,在动态作用域中,所有变量共享一张全局对照表,而在进入函数时,会创建一张动态对照表,这张表是所有函数共享的,所有的函数都可以读取到,这就造成了上述现象的发生。
总结来说,在动态作用域中,每个变量在查找对应的地址时,按照由近到远的顺序来查找。这造成了函数嵌套调用时相互影响的现象,为了解决这种现象,我们可以给每个函数使用单独的对照表进行存储变量,这就是静态作用域。
静态作用域
静态作用域每个函数单独使用一张变量表。计算机在寻找变量时,首先从函数内部的变量表中进行查找,如果找不到则到全局变量表中进行查找。这很好的解决了动态作用域下函数嵌套调用时产生的问题。
然而,静态作用域在使用时也存在一些问题。一是嵌套函数的问题,以Python为例:
1 | x = "global" |
在该嵌套函数中,bar
函数中输出的x
乍一看应该是foo
,然而,在Python
2中,函数bar
在查找变量x
时,首先查找局部对照表,没找到时直接在全局对照表中进行查找,因此输出结果是global
。这种设计给程序带来了很多误解。直到Python
3中才解决了这个问题。
第二个问题是外部作用域的再绑定问题。当我们想要在函数中修改一个外部作用域的值时,反而会创建一个新的变量,从而无法修改外部作用域的值。例如:
1 | x = "global" |
在Python 3.0中,引入了nonlocal
关键字来解决这个问题:
1 | x = "global" |
小结
计算机技术的发展带来了更强大的计算能力,从而出现了越来越复杂的程序。命名与作用域的发展凸显了当程序规模很大时,为变量和函数命名时人与计算机之间的矛盾。编程语言中的任何特性都并非凭空产生,而是为了解决某些问题而出现的。