@@ -8,154 +8,173 @@ title: 基础知识
8
8
## 函数和变量 ##
9
9
10
10
elisp 中定义一个函数是用这样的形式:
11
- {% highlight cl %}
11
+
12
+ ``` cl
12
13
(defun function-name (arguments-list)
13
14
"document string"
14
15
body)
15
- {% endhighlight %}
16
+ ```
16
17
17
18
比如:
18
- {% highlight cl %}
19
+
20
+ ``` cl
19
21
(defun hello-world (name)
20
22
"Say hello to user whose name is NAME."
21
23
(message "Hello, %s" name))
22
- {% endhighlight %}
24
+ ```
23
25
24
26
其中函数的文档字符串是可以省略的。但是建议为你的函数(除了最简单,不作为接口的)都加上文档字符串。这样将来别人使用你的扩展或者别人阅读你的代码或者自己进行维护都提供很大的方便。
25
27
26
28
在 emacs 里,当光标处于一个函数名上时,可以用 ` C-h f ` 查看这个函数的文档。比如前面这个函数,在 ` *Help* ` 缓冲区里的文档是:
27
29
28
- hello-world is a Lisp function.
29
- (hello-world name)
30
-
31
- Say hello to user whose name is name.
30
+ ```
31
+ hello-world is a Lisp function.
32
+ (hello-world name)
33
+
34
+ Say hello to user whose name is name.
35
+ ```
32
36
33
37
如果你的函数是在文件中定义的。这个文档里还会给出一个链接能跳到定义的地方。
34
38
35
39
要运行一个函数,最一般的方式是:
36
- {% highlight cl %}
40
+
41
+ ``` cl
37
42
(function-name arguments-list)
38
- {% endhighlight %}
43
+ ```
39
44
40
45
比如前面这个函数:
41
- {% highlight cl %}
46
+
47
+ ``` cl
42
48
(hello-world "Emacser") ; => "Hello, Emacser"
43
- {% endhighlight %}
49
+ ```
44
50
45
51
每个函数都有一个返回值。这个返回值一般是函数定义里的最后一个表达式的值。
46
52
47
53
elisp 里的变量使用无需象 C 语言那样需要声明,你可以用 setq 直接对一个变量赋值。
48
- {% highlight cl %}
54
+
55
+ ``` cl
49
56
(setq foo "I'm foo") ; => "I'm foo"
50
57
(message foo) ; => "I'm foo"
51
- {% endhighlight %}
58
+ ```
52
59
53
60
和函数一样,你可以用 C-h v 查看一个变量的文档。比如当光标在 foo 上时用 ` C-h v ` 时,文档是这样的:
54
61
55
- foo's value is "I'm foo"
56
-
62
+ ```
63
+ foo's value is "I'm foo"
57
64
58
- Documentation:
59
- Not documented as a variable.
65
+ Documentation:
66
+ Not documented as a variable.
67
+ ```
60
68
61
69
有一个特殊表达式(special form)` defvar ` ,它可以声明一个变量,一般的形式是:
62
- {% highlight cl %}
70
+
71
+ ``` cl
63
72
(defvar variable-name value
64
73
"document string")
65
- {% endhighlight %}
74
+ ```
66
75
67
76
它与 ` setq ` 所不同的是,如果变量在声明之前,这个变量已经有一个值的话,用 ` defvar ` 声明的变量值不会改变成声明的那个值。另一个区别是 ` defvar ` 可以为变量提供文档字符串,当变量是在文件中定义的话,` C-h v ` 后能给出变量定义的位置。比如:
68
- {% highlight cl %}
77
+
78
+ ``` cl
69
79
(defvar foo "Did I have a value?"
70
80
"A demo variable") ; => foo
71
81
foo ; => "I'm foo"
72
82
(defvar bar "I'm bar"
73
83
"A demo variable named \"bar\"") ; => bar
74
84
bar ; => "I'm bar"
75
- {% endhighlight %}
85
+ ```
76
86
77
87
用 ` C-h v ` 查看 foo 的文档,可以看到它已经变成:
78
88
79
- foo's value is "I'm foo"
80
-
89
+ ```
90
+ foo's value is "I'm foo"
81
91
82
- Documentation:
83
- A demo variable
92
+ Documentation:
93
+ A demo variable
94
+ ```
84
95
85
96
由于 elisp 中函数是全局的,变量也很容易成为全局变量(因为全局变量和局部变量的赋值都是使用 ` setq ` 函数),名字不互相冲突是很关键的。所以除了为你的函数和变量选择一个合适的前缀之外,用 ` C-h f ` 和 ` C-h v ` 查看一下函数名和变量名有没有已经被使用过是很关键的。
86
97
87
98
## 局部作用域的变量 ##
88
99
89
100
如果没有局部作用域的变量,都使用全局变量,函数会相当难写。elisp 里可以用 let 和 ` let* ` 进行局部变量的绑定。` let ` 使用的形式是:
90
- {% highlight cl %}
101
+
102
+ ``` cl
91
103
(let (bindings)
92
104
body)
93
- {% endhighlight %}
105
+ ```
94
106
95
107
bingdings 可以是 (var value) 这样对 var 赋初始值的形式,或者用 var 声明一个初始值为 ` nil ` 的变量。比如:
96
- {% highlight cl %}
108
+
109
+ ``` cl
97
110
(defun circle-area (radix)
98
111
(let ((pi 3.1415926)
99
112
area)
100
113
(setq area (* pi radix radix))
101
114
(message "直径为 %.2f 的圆面积是 %.2f" radix area)))
102
115
(circle-area 3)
103
- {% endhighlight %}
116
+ ```
104
117
105
118
` C-h v ` 查看 area 和 pi 应该没有这两个变量。
106
119
107
120
` let* ` 和 ` let ` 的使用形式完全相同,唯一的区别是在 ` let* ` 声明中就能使用前面声明的变量,比如:
108
- {% highlight cl %}
121
+
122
+ ``` cl
109
123
(defun circle-area (radix)
110
124
(let* ((pi 3.1415926)
111
125
(area (* pi radix radix)))
112
126
(message "直径为 %.2f 的圆面积是 %.2f" radix area)))
113
- {% endhighlight %}
127
+ ```
114
128
115
129
## lambda 表达式 ##
116
130
117
131
可能你久闻 lambda 表达式的大名了。其实依我的理解,lambda 表达式相当于其它语言中的匿名函数。比如 perl 里的匿名函数。它的形式和 ` defun ` 是完全一样的:
118
132
119
- {% highlight cl %}
133
+ ``` cl
120
134
(lambda (arguments-list)
121
135
"documentation string"
122
136
body)
123
- {% endhighlight %}
137
+ ```
124
138
125
139
调用 lambda 方法如下:
126
- {% highlight cl %}
140
+
141
+ ``` cl
127
142
(funcall (lambda (name)
128
143
(message "Hello, %s!" name)) "Emacser")
129
- {% endhighlight %}
144
+ ```
130
145
131
146
你也可以把 lambda 表达式赋值给一个变量,然后用 ` funcall ` 调用:
132
- {% highlight cl %}
147
+
148
+ ``` cl
133
149
(setq foo (lambda (name)
134
150
(message "Hello, %s!" name)))
135
151
(funcall foo "Emacser") ; => "Hello, Emacser!"
136
- {% endhighlight %}
152
+ ```
137
153
138
154
lambda 表达式最常用的是作为参数传递给其它函数,比如 ` mapc ` 。
139
155
140
156
## 控制结构 ##
141
157
142
158
### 顺序执行 ###
143
159
一般来说程序都是按表达式顺序依次执行的。这在 ` defun ` 等特殊环境中是自动进行的。但是一般情况下都不是这样的。比如你无法用 ` eval-last-sexp ` 同时执行两个表达式,在 if 表达式中的条件为真时执行的部分也只能运行一个表达式。这时就需要用 ` progn ` 这个特殊表达式。它的使用形式如下:
144
- {% highlight cl %}
160
+
161
+ ``` cl
145
162
(progn A B C ...)
146
- {% endhighlight %}
163
+ ```
147
164
148
165
它的作用就是让表达式 A, B, C 顺序执行。比如:
149
- {% highlight cl %}
166
+
167
+ ``` cl
150
168
(progn
151
169
(setq foo 3)
152
170
(message "Square of %d is %d" foo (* foo foo)))
153
- {% endhighlight %}
171
+ ```
154
172
155
173
### 条件判断 ####
156
174
157
175
elisp 有两个最基本的条件判断表达式 ` if ` 和 ` cond ` 。使用形式分别如下:
158
- {% highlight cl %}
176
+
177
+ ``` cl
159
178
(if condition
160
179
then
161
180
else)
@@ -164,10 +183,11 @@ elisp 有两个最基本的条件判断表达式 `if` 和 `cond`。使用形式
164
183
(case2 do-when-case2)
165
184
...
166
185
(t do-when-none-meet))
167
- {% endhighlight %}
186
+ ```
168
187
169
188
使用的例子如下:
170
- {% highlight cl %}
189
+
190
+ ``` cl
171
191
(defun my-max (a b)
172
192
(if (> a b)
173
193
a b))
@@ -179,34 +199,36 @@ elisp 有两个最基本的条件判断表达式 `if` 和 `cond`。使用形式
179
199
(t (+ (fib (- n 1))
180
200
(fib (- n 2))))))
181
201
(fib 10) ; => 55
182
- {% endhighlight %}
202
+ ```
183
203
184
204
还有两个宏 ` when ` 和 ` unless ` ,从它们的名字也就能知道它们是作什么用的。使用这两个宏的好处是使代码可读性提高,` when ` 能省去 ` if ` 里的 ` progn ` 结构,` unless ` 省去条件为真子句需要的的 ` nil ` 表达式。
185
205
186
206
### 循环 ###
187
207
188
208
循环使用的是 ` while ` 表达式。它的形式是:
189
- {% highlight cl %}
209
+
210
+ ``` cl
190
211
(while condition
191
212
body)
192
- {% endhighlight %}
213
+ ```
193
214
194
215
比如:
195
- {% highlight cl %}
216
+
217
+ ``` cl
196
218
(defun factorial (n)
197
219
(let ((res 1))
198
220
(while (> n 1)
199
221
(setq res (* res n)
200
222
n (- n 1)))
201
223
res))
202
224
(factorial 10) ; => 3628800
203
- {% endhighlight %}
225
+ ```
204
226
205
227
## 逻辑运算 ##
206
228
207
229
条件的逻辑运算和其它语言都是很类似的,使用 ` and ` 、` or ` 、` not ` 。` and ` 和 ` or ` 也同样具有短路性质。很多人喜欢在表达式短时,用 ` and ` 代替 ` when ` ,` or ` 代替 ` unless ` 。当然这时一般不关心它们的返回值,而是在于表达式其它子句的副作用。比如 ` or ` 经常用于设置函数的缺省值,而 ` and ` 常用于参数检查:
208
230
209
- {% highlight cl %}
231
+ ``` cl
210
232
(defun hello-world (&optional name)
211
233
(or name (setq name "Emacser"))
212
234
(message "Hello, %s" name)) ; => hello-world
@@ -218,10 +240,11 @@ elisp 有两个最基本的条件判断表达式 `if` 和 `cond`。使用形式
218
240
(= (/ n (sqrt n)) (sqrt n))))
219
241
(square-number-p -1) ; => nil
220
242
(square-number-p 25) ; => t
221
- {% endhighlight %}
243
+ ```
222
244
223
245
## 函数列表 ##
224
- {% highlight cl %}
246
+
247
+ ``` cl
225
248
(defun NAME ARGLIST [DOCSTRING] BODY...)
226
249
(defvar SYMBOL &optional INITVALUE DOCSTRING)
227
250
(setq SYM VAL SYM VAL ...)
@@ -237,6 +260,6 @@ elisp 有两个最基本的条件判断表达式 `if` 和 `cond`。使用形式
237
260
(or CONDITIONS ...)
238
261
(and CONDITIONS ...)
239
262
(not OBJECT)
240
- {% endhighlight %}
263
+ ```
241
264
242
265
0 commit comments