symbol 类型是 Elisp 中比较复杂的一个类型之一,每一个 symbol 都有一个 name 。这里 只介绍 symbol 的 name 的格式。symbol 可以用来表示 varible, function, 还可以用来 标识一个唯一的值,例如一种颜色,一周星期的名字,可以说 symbol 是使用最广泛的一种 类型。
symbol name 可以任意字符。这一点和很多其他非 Lisp 类的语言有很大区别,一般语言中, 用来表示变量的名字都不能任意取,例如: C 语言中便亮名字必须以非数字开头,仅有字 母,下划线和数字组成,而且还不能是保留字,例如 for , while 等。但是在 ELisp 中完 全没有什么保留字。
但是有一些特殊字符会被特殊解释,例如 ( , 1.2 , ) , 等等,要想 symbol name 中含 有这些东西,那么就必须用斜杠使之转义。然而,让名字中含有一些特殊字符如果并不能增 强可读性,就是给自己找麻烦。
每一个 symbol 有 4 个 cell 用来存储不同的信息。
(setq var 'a-symbol) (symbol-name 'var) ;; 返回 "var" (symbol-name var) ;; 返回 "a-symbol"
symbol 的 name 是唯一的,两个重名的 symbol 是同一 个 symbol。 Elisp 的解释器保证了这一点,在读取一个 symbol 的时候,首先查找是否有已经存在的 symbol , 如果有,则用原来的,如果没有就新建一个。
可以用函数 symbol-value 来得到一个 symbol 的 value 。
boundp 可以判断一个 symbol 时候有 symbol-value
当 symbol 作为一个 varible 的时候,会得到他的
symbol value 。在对一个 symbol 求值的时候,就会得
到 symbol value 。常用的设置 symbol value 的办法就
是用 setq 。
(setq a 1) (setq b 2) (list a b) ;; 返回 (1 2)
当一个 symbol 作为一个 function , 取 symbol 对应的函数。可以用下面的函数得到一 个symbol 中的函数。
symbol-function, 注意下面的区别。一个 symbol 可以同时拥 有 4 个属性
(setq add (lambda (a b) (- a b))) ;; 注意 add 现在的 symbol-value 是一个函数 (fboundp 'add) ;; 返回 nil , add 不对应一个的函数 (add 1 1) ;; 会产生错误 (defun add (a b) (+ a b)) ;; 注意这时 add 就对应一个函数。 (add 1 3) ;; 返回 4 , 1 + 3 (funcall add 3 1) ;; 返回 3 - 1 , 因为 add 作为参数的时候,取 value , ;; 下面的为了加深理解 (funcall (symbol-value 'add) 3 1) ;; 返回 2 (funcall (symbol-function 'add) 3 1) ;; 返回 4
当 emacs 的 elisp 解释器碰到一个 symbol 的时候, 注意 symbol 和 quote 的区别。 `var= 等同于
(quote var),而后者是一个 list ,其中有两个 symbol , elisp 认为第 一个 symbol 是一个函数,取 symbol 中.
每一个 elisp 碰到的每一个 symbol , 都会在 obarray 中搜索。 obarray 是一个数组, 用于 emacs 内部的 hash 结构,用于快速查找 symbol。
(setq b 1) b ;; 返回 1 (unintern 'b) b ;; 产生错误,symbol b 不存在了。 (set (intern "b") 1) ;; 几乎等同于 (setq b 1) b ;; 返回 1
可以创建自己的这种结构,类似于 hash 结构。速度很快。
(setq myobarray (make-vector 1511 0)) ;; 1511 是一个质数,更加有效率 (set (intern "a" myobarray) 1) (set (intern "b" myobarray) 2) (set (intern "c" myobarray) 3) ;; 打印 ;;a --> 1 ;;b --> 2 ;;c --> 3 (mapatoms (lambda (s) (print (format "%s -->%d" (symbol-name s) (symbol-value s)))) myobarray) (intern-soft "a" myobarray) ;; 返回一个 symbol (intern-soft "x" myobarray) ;; 返回 nil (unintern "a" myobarray) ;; 删除一个 symbol
如果
myobarray中不存在某个 symbol ,intern函数会自动创建一个,然后返回这个 创建的 symbol. 所以这个函数不能判断myobarray是否存在某个 symbol ,=intern-soft= 可以实现这个功能,对于不存在的 symbol, 该函数返回nil
下面的例子加强理解
(setq a nil) (setq my-obarray-list (cons (make-vector 1511 0) nil)) (setq car-of-obarray-list (car my-obarray-list)) (set (intern "a" car-of-obarray-list) "hello") (symbol-value (intern-soft "a" (car my-obarray-list))) ;; 返回 "hello" (eq (intern "a" car-of-obarray-list) 'a) ;; 返回 nil , 两个 a 在不同的 obarray 中。 (eq (symbol-name (intern "a" car-of-obarray-list)) (symbol-name 'a)) ;; 返回nil, (eq "a" "a") ;; 返回 nil (equal (symbol-name (intern "a" b)) (symbol-name 'a)) ;; 返回 t (eq (intern "a" car-of-obarray-list) (intern "a" (car my-obarray-list))) ;; 返回 t