重用复杂数据结构
有时,我们会希望函数是和其他语言中的函数一样的运行,即在不修改传入参数的情况下返回个新值,而有时,我们又想让函数重用或在数据的原有基础上进行修改 —— 想想 [append](http://www.lispworks.com/documentation/HyperSpec/Body/f_append.htm) 和 [nconc](http://www.lispworks.com/documentation/HyperSpec/Body/f_nconc.htm) 之间的区别吧。或者是 C 语言函数中的传值与传址。
要想实现上面所说的功能,可以使用可选(关键词)参数。如:假设需要实现一个名为 complex-matrix-stuff 的函数,该函数有两个参数 m1 和 m2,然后函数会计算出矩阵 m1 和 m2 运算结果并返回所得矩阵的大小,也就是说,在调用函数时将会由 (make-appropriate-result-matrix-for m1 m2) 创建一个空矩阵用来存储结果。
标准的教科书式的实现方法看起来和下面的差不多:
(defun complex-matrix-stuff (m1 m2)(let ((result (make-appropriate-result-matrix-for m1 m2)));; ... compute storing the results in RESULTresult))
然后就可以这样调用:
(setq some-matrix (complex-matrix-stuff A B))
但为什么不写成下面这种形式呢?
(defun complex-matrix-stuff (m1 m2&optional(result(make-appropriate-result-matrix-for m1 m2)));; ... compute storing the results in RESULTresult)
现在就有两种方法了,而且依然可以像之前一样使用:
(setq some-matrix (complex-matrix-stuff A B))
但也可以直接将结果赋给已经存在的变量:
(complex-matrix-stuff A B some-appropriate-matrix-I-built-before)
或者这样:
(setq some-other-matrix(complex-matrix-stuff A B some-appropriate-matrix-I-built-before))
得到的结果是一样的:
* (eq some-other-matrix some-appropriate-matrix-I-built-before)T
合并新的序列时用 ADJUST-ARRAY 而不是 SUBSEQ
CL 中大部分对序列操作的函数都可以使用 start 和 end 关键字,因此,可以不创建子字符串就进行操作。即,不要像下面这样:
(count #\a (subseq long-string from to))
而是要这样使用:
(count #\a long-string :start from :end to)
上面这种做法得到的结果与之前的是一样的,但不会创建不必要的中间子序列。
然而,有时创建新的数据无法避免。这时就可以将字符串当作是哈希表的关键词。当查找的键是另一个字符串的子串时,可以像下面这样:
(gethash (subseq original-string from to)hash-table)
但没必要这么做。可以创建一个可变字符串,然后通过 [adjust-array](http://www.lispworks.com/documentation/HyperSpec/Body/f_adjust.htm)对该字符串进行重用:
(let ((substring (make-array 0:element-type 'character:displaced-to "":displaced-index-offset 0)));; more code(gethash(adjust-array substring (- to from):displaced-to original-string:displaced-index-offset from)hash-table);; even more code)
