用 (make-vector 2 (make-vector 3 0))
定义一个二行三列数组似乎符合直觉,但有陷阱,同样是修改 [0, 0]
,对比:
(let ((vec (make-vector 2 (make-vector 3 0))))
(setf (elt (elt vec 0) 0) 100)
vec)
;; => [[100 0 0] [100 0 0]]
(let ((vec [[0 0 0]
[0 0 0]]))
(setf (elt (elt vec 0) 0) 100)
vec)
;; => [[100 0 0] [0 0 0]]
根源在于 make-vector
版本中,(elt vec 0)
和 (elt vec 1)
是 eq
的(同一个对象),正确的做法看起来麻烦些:
(defun my-make-two-dims-array (width height)
(let ((vec (make-vector height nil)))
(dotimes (i height vec)
(setf (elt vec i) (make-vector width 0)))))
(let ((vec (my-make-two-dims-array 3 2)))
(setf (elt (elt vec 0) 0) 100)
vec)
;; => [[100 0 0] [0 0 0]]
2 个赞
如果 make-vector
第二个参数是 object 的话,就是指针赋值了:
DEFUN ("make-vector", Fmake_vector, Smake_vector, 2, 2, 0,
doc: /* Return a newly created vector of length LENGTH, with each element being INIT.
See also the function `vector'. */)
(Lisp_Object length, Lisp_Object init)
{
CHECK_NATNUM (length);
struct Lisp_Vector *p = allocate_vector (XFASTINT (length));
for (ptrdiff_t i = 0; i < XFASTINT (length); i++)
p->contents[i] = init;
return make_lisp_ptr (p, Lisp_Vectorlike);
}
所以不管几维,修改的都是同一个 object。
1 个赞
嗯,make-list
也是,平时很少需要 初始化 List,一般都一个一个往里面加值,不会受此影响。Emacs Lisp 有不少和 Mutable 相关的陷阱。
那个函数有点像C语言的
(defun my-make-two-dims-array (width height)
(apply 'vector
(mapcar '(lambda (A)(make-vector width 0))
(make-string height ?A))))
Emacs Lisp里除了基本类型以外都是传递指针的吧?
那么平时注意使用这种会复制 参数的函数的时候不要直接传入基本类型以外的值,应该就可以避免坑了。
Emacs Lisp 有不少和 Mutable 相关的陷阱。
还有哪些啊?
glgl-schemer:
求值顺序而已。
明明是 pass by reference 和 evaluation order 有啥关系。而且又不是 Scheme,众所周知 Emacs Lisp 是严格从左向右求值的。
这里有个类似 cl 的 make-array 实现:EmacsWiki: cl-array.el
2 个赞
LdBeth:
和 evaluation order 有啥关系。
先求(make-vector 3 0)
,求完当参数了。
在ELisp里,我唯一初始化 过的东西就是keymap variable。别的东西都是直接手写出来……
1 个赞
LdBeth
2018 年12 月 5 日 19:18
12
那不就是 pass by reference 么,和 evaluation order 啥关系,call by value 语言参数永远要先求值,evaluation order 只说明参数之间的求值先后
1 个赞
后来想了一下,还是思维方式不一样。
我对主楼产生了这种误解的原因在于以为他觉得(make-vector 3 0)
会求值两次。
而你的想法是认为他觉得会把整个vector复制下来。
争这个有什么用。。。