2.10 变量 (Variables)

let 是一个最常用的 Common Lisp 的操作符之一,它让你引入新的局部变量(local variable):

  1. > (let ((x 1) (y 2))
  2. (+ x y))
  3. 3

一个 let 表达式有两个部分。第一个部分是一组创建新变量的指令,指令的形式为 (variable expression) 。每一个变量会被赋予相对应表达式的值。上述的例子中,我们创造了两个变量, xy ,分别被赋予初始值 12 。这些变量只在 let 的函数体内有效。

一组变量与数值之后,是一个有表达式的函数体,表达式依序被求值。但这个例子里,只有一个表达式,调用 + 函数。最后一个表达式的求值结果作为 let 的返回值。以下是一个用 let 所写的,更有选择性的 askem 函数:

  1. (defun ask-number ()
  2. (format t "Please enter a number. ")
  3. (let ((val (read)))
  4. (if (numberp val)
  5. val
  6. (ask-number))))

这个函数创建了变量 val 来储存 read 所返回的对象。因为它知道该如何处理这个对象,函数可以先观察你的输入,再决定是否返回它。你可能猜到了, numberp 是一个谓词,测试它的实参是否为数字。

如果使用者不是输入一个数字, ask-number 会持续调用自己。最后得到一个只接受数字的函数:

  1. > (ask-number)
  2. Please enter a number. a
  3. Please enter a number. (ho hum)
  4. Please enter a number. 52
  5. 52

我们已经看过的这些变量都叫做局部变量。它们只在特定的上下文里有效。另外还有一种变量叫做全局变量(global variable),是在任何地方都是可视的。 [2]

你可以给 defparameter 传入符号和值,来创建一个全局变量:

  1. > (defparameter *glob* 99)
  2. *GLOB*

全局变量在任何地方都可以存取,除了在定义了相同名字的区域变量的表达式里。为了避免这种情形发生,通常我们在给全局变量命名时,以星号作开始与结束。刚才我们创造的变量可以念作 “星-glob-星” (star-glob-star)。

你也可以用 defconstant 来定义一个全局的常量:

  1. (defconstant limit (+ *glob* 1))

我们不需要给常量一个独一无二的名字,因为如果有相同名字存在,就会有错误产生 (error)。如果你想要检查某些符号,是否为一个全局变量或常量,使用 boundp 函数:

  1. > (boundp '*glob*)
  2. T