let 避免命名冲突

let 特殊形式可以避免命名冲突。let 会创建一个 局部变量(local variable) 名称,该名称会覆盖 let 表达式外部对同名变量的使用 (计算机术语中,我们称之为对变量进行绑定(binding))。 这就好比在主人家中,他提到“家”时,指的是他的房子,而不是你的。 (用于命名函数参数的符号,也以完全相同的方式绑定为局部变量。 See The defun Macro。)

另一种理解 let 的方式是:它在代码中划定了一个专属区域: 在 let 表达式体内,你声明的变量拥有自身的局部含义; 在 let 体外,它们拥有其他含义(或根本未定义)。 这意味着在 let 体内,对 let 声明的变量使用 setq 会修改该名称的**局部**变量。而在 let 体外 (例如调用别处定义的函数时),对 let 声明的变量使用 setq 不会 影响该局部变量。10

let 可以同时创建多个变量。此外,let 会为创建的每个变量赋予初始值,要么是你指定的值,要么是 nil。 (术语中,这就是将变量绑定到值。)let 创建并绑定变量后, 会执行 let 体内的代码,并返回体内最后一个表达式的值, 作为整个 let 表达式的值。(“执行(Execute)”是用于描述对列表求值的术语, 源自“付诸实践”的含义(引自《牛津英语词典》)。 由于对表达式求值是为了执行某个动作,“执行(execute)”逐渐成为“求值(evaluate)”的同义词。)


Footnotes

(10)

这里描述的是采用 “词法绑定(lexical binding)” 风格时 let 的行为(see let 绑定变量的方式)。