控制流
區塊
區塊的基本操作符:progn、block、tagbody
progn:對主體中的每個表達式依次進行求值,返回最後一個表達式的值。
如:
(progn
(format t "a")
(format t "b")
(+ 1 1))
輸出爲:ab23
block:像一個帶有名字及緊急出口的progn。第一個參數爲符號。可在block中使用return-from 符號跳出block。
例子:
(block head
(format t "one")
(return-from head 'over)
(format t "two"))
輸出爲:oneOVER
由例子可以看出,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