变量的基础知识
引入新变量的一种方式是使用LET特殊操作符
(let (variable*) body-form*)
- 当这个LET形式被求值时,所有的初始值形式都将首先被求值,然后创建出新的绑定,并在形式提被执行之前将初始化到适当的初始值上
- 在LET形式体中,变量将会使用在LET中的赋值
- 如果LET形式体执行结束,那么这些变量名会重新引用执行LET之前它们所引用的内容
(defun foo(x)
(format t "P:~a~%"x)
(let ((x 2))
(format t "O:~a~%" x)
(let ((x 3))
(format t "I:~a~%" x)
)
(format t "O:~a~%" x)
)
(format t "P:~a~%"x)
)
; P:1
; O:2
; I:3
; O:2
; P:1
另外一个形式是LET的变体,LET*
两者的区别在于,在一个LET中,被绑定的变量名只能用在LET的形式体之内
在LET*中,每个变量的初始值形式,都可以引用到那些在变量列表中早先引入的变量
词法变量和闭包
词法作用域的变量只能由那些在文本上位于绑定形式之内的代码所引用,在词法作用域中的变量叫做词法变量
(let ((count 0)) #'(lambda () (setf count (1+count))))
在上面这个例子中,当控制流进入LET形式时所创建的count绑定将被尽可能地保留下来,只要某处保持了一个对LET形式所返回的函数对象的引用即可,这个匿名函数被称为一个闭包,因为它“封闭包装”了有LET创建的绑定
- 闭包捕捉的是绑定(引用)而不是变量的值
- 闭包不仅可以访问它所闭合的变量值,还可以对其不予在闭包被调用时不断变量的新值
将表达式所创建的闭包捕捉到一个全局变量中
(defparameter *fn* (let ((count 0)) #'(lambda () (setf count (+ 1 count)))))
; CL-USER> (funcall *fn*)
; 1
; CL-USER> (funcall *fn*)
; 2
; CL-USER> (funcall *fn*)
; 3
动态变量
可以使用DEFVAR
和DEFPARAMETER
来定义全局变量
两种形式都接受一个变量名、一个初始值以及一个可选的文档字符串
DEFPARAMETER
总是将初始值赋给命名的变量,而DEFVAR
形式也可以不带初始值来使用,从而在不给定其值的情况下定义一个全局变量
全局变量的命名约定是name\
用LET进行绑定会覆盖掉对全局变量的绑定
(defvar *x* 10)
(defun foo() (format t "X:~d~%" *x*))
(foo)
(let ((*x* 20)) (foo))
(foo)
;退出LET之后,依然会使用原来的绑定
; X:10
; X:20
; X:10
LET进行的是动态绑定
常量
可以使用DEFCONSTANT
来进行定义常亮
形式如下
(defconstant name initial-value-from [document-string ])
赋值
可以使用setf
来进行赋值操作
(setf place value)
在lisp中,可以使用setf
用来对许多结构进行赋值
其他修改位置的方式
可以使用宏INCF
和DECF
,它们以默认为1的特定数量对一个位置的值进行递增和递减
(incf x) = (setf x (+ x 1))
(decf x) = (setf x (- x 1))
(incf x 10) = (setf x (+ x 10))
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END
暂无评论内容