控制流
区块
区块的基本操作符:progn、block、tagbody
progn:对主体中的每个表达式依次进行求值,返回最后一个表达式的值。
如:
(progn
(format t "a")
(format t "b")
(+ 1 1))
输出为:ab
23
block:像一个带有名字及紧急出口的progn。第一个参数为符号。可在block中使用return-from 符号跳出block。
例子:
(block head
(format t "one")
(return-from head 'over)
(format t "two"))
输出为:one
OVER
由例子可以看出,block之后的符号为block块的名字,通过return-from block名字即可跳出block。
return-from:第一个参数为区块名,第二个参数为:跳出时的返回值
若想不使用块名,跳出当前块,则可以使用return 返回值,即可。
1.许多接收一个表达式主体的操作符都隐含在一个叫做nil区块中。
2.使用defun定义的函数,都隐含在一个与函数同名的区块中。所以,在函数中可用return-from 跳出函数并返回值
语境
用来代替表达式分组的操作符是letlet:接收一个代码主体,允许在代码主体中设置新变量。第一个参数为变量的初始过程。
如:(let ((x 1) (y 1)) (+ x y))→2
let创造出一个新的词法语境,就像C语言中的代码块,在此语境中的变量为局部变量。
注意:由let创建的变量值,不能依赖其他由同一个let创造的变量。
如:
(let ((x 1)
(y x))
(+ x y))
其中,第一个let创建了一个x变量,可以在let语境内使用,但不能将此变量用于此let中创建另一个变量的初始值。要想使用则需要用let*。
let*例子:
(let* (x 1)
(y x)
(+ x y))
输出:2
其中,let*等价于
(let ((x 1)
(let (y x)
(+ x y)))
deftructuring-bind:这是一个通用化的let,是一个宏。接收单一变量,接收一个模式:一个或多个变量形成的树,并将它们与某个实际的树所对应部分做绑定。
例子:(destructuring-bind (w (x y) . z)'(a (b c) d e) (list w x y z))→(A B C (D E))
条件
if格式:if 条件 语句1 语句2
说明:若条件为真,则执行语句1,否则执行语句2
例子:
(defun max-my (x y)
(if (> x y) x y))
测试代码:
CL-USER> (max-my 1 2)
2
when
格式:when 条件 语句1 语句2 ....
说明:若条件满足则开始执行when中的所有语句,返回最后一条语句的值
例子:
(defun say (flag)
(when (equal flag "talk")
(format t "hello!")
(format t "What's your name?")))
测试代码:
CL-USER> (say "talk")
hello!What's your name?
NIL
unless与when类似,when是条件为真,执行语句。 unless是条件为假,执行语句。
cond
格式:cond (条件1 语句1 条件2 语句2...)
说明:条件1为真,执行语句1,否则判断条件2是否为真,为真执行语句2,否则判断条件3....
例子:
(defun my-num-range (x)
(cond ((> x 10) (format t "~A>10~%" x))
((> x 5) (format t "~A>5~%" x))
((> x 0) (format t "~A>0~%" x))
(t (format t "~A<0~%" x))))
测试代码:
CL-USER> (my-num-range 4)
4>0
NIL
其中,cond可以理解为只有当条件为真时,才会停止判断,条件为真的其后的语句。最后一句,应为t永远为真,所以将此句作为缺省的条件式。
case
格式:case 关键字变量 (关键字或关键字列表 语句)...
说明:关键字的值会和下面的每个关键字或在关键字列表中查找,若有相等的则执行其后的语句。缺省子句可用的键值可为t或otherwise。
typecase与case相似,typecase的每个键值应为类型修饰符。第一个参数与键值比较的函数使用typep。
迭代
do格式:do (变量规格说明的列表) (条件 语句1) 语句2
说明:变量规格的说明列表为:迭代变量名,迭代初始值,下一个迭代值。条件为结束迭代的条件,当满足条件时执行语句1并停止迭代,否则执行迭代体语句,即:语句2。
例子:
(defun do-test (x)
(do ((i 0 (+ i 1)))
((= i x) 'done)
(format t "~A," i)))
测试代码:
CL-USER> (do-test 5)
0,1,2,3,4,
DONE
do*:do*与do的关系相当于let*和let的关系。dolist
格式:dolist (迭代变量 列表 迭代结束返回值) 迭代体语句
说明:当迭代开始时,会从列表第一个元素开始,依次赋给迭代变量,然后执行迭代体语句,当迭代到列表最后一个元素之后,则返回迭代结束返回值。迭代结束返回值也可以是一个语句。
例子:
(defun dolist-test (lst)
(dolist (x lst (format t "~%list over"))
(format t "~A," x)))
测试代码:
CL-USER> (dolist-test '(1 2 3 4))
1,2,3,4,
list over
NIL
dotimes
格式:dotimes (迭代变量 N 迭代结束返回值) 迭代体语句
说明:给定一个整数N,则会从整数0开始,直到N-1
例子:
(defun dotimes-test (n)
(dotimes (x n 'over)
(format t "~A," x)))
测试代码:
CL-USER> (dotimes-test 4)
0,1,2,3,
OVER
多值
values:将传入的参数返回。若将values作为函数的最后一个表达式,则values返回的值将作为函数返回值测试代码:
CL-USER> (values 'a 1 (+ 1 1))
A
1
2
multiple-value-bind:接受多个值。若变量的数量大于数值的数量,剩余变量为nil。若数值的数量大于变量的数据,则多余的值舍去。
测试代码:
CL-USER> (multiple-value-bind (x y z) (values 1 2 3) (list x y z))
(1 2 3)
CL-USER> (multiple-value-bind (x y z) (values 1 2) (list x y z))
(1 2 NIL)
CL-USER> (multiple-value-bind (x y z) (values 1 2 3 4) (list x y z))
(1 2 3)
multiple-value-call:将多值作为参数传给函数。第一个参数为函数,第二个参数为多值
测试代码:
CL-USER> (multiple-value-call #'+ (values 1 2 3))
6
mutiple-value-list:将传入的多值创建一个列表并返回。
中止
catch与throw
使用catch定义一个标签,在代码任何地方,一个带有特定标签的throw都会导致catch的表达式直接返回。
例子:
(defun sup()
(catch 'quit
(sub)
(format t "aaa")))
(defun sub()(throw 'quit 'done))
测试代码:
CL-USER> (sup)
DONE