【发布时间】:2018-06-30 00:49:38
【问题描述】:
来自 C++ 背景,我试图弄清楚参数是如何传递给 Elisp 中的方法的。虽然我承认措辞可能会有所不同,但我想知道它是否更接近 C++ 通过引用传递或按值传递的想法?如果我改变方法本身的参数,它会改变函数调用中传入的参数吗?
【问题讨论】:
标签: lisp parameter-passing elisp
来自 C++ 背景,我试图弄清楚参数是如何传递给 Elisp 中的方法的。虽然我承认措辞可能会有所不同,但我想知道它是否更接近 C++ 通过引用传递或按值传递的想法?如果我改变方法本身的参数,它会改变函数调用中传入的参数吗?
【问题讨论】:
标签: lisp parameter-passing elisp
所有 Lisps(Emacs Lisp、Common Lisp)总是按值传递参数:
(defparameter x 42) ; defconst in Emacs Lisp
(defun test (x)
(setq x 10))
(test x)
==> 10
x
==> 42
但是请注意,有些值实际上是指针(或者,更确切地说,是带有组件的对象),因此函数可以通过副作用修改它们的内容:
(defparameter x (list 1 2))
(defun test (x)
(setf (first x) 42
(second x) 24
x 17))
(test x)
==> 17
x
==> (42 24)
PS1。参照。 When to use ' (or quote) in Lisp? -- “引用的参数”也会被评估:评估会去掉引用。
PS2。参照。 add-to-list - 它接受一个符号(变量名)并修改它的值。这仅适用于全局动态变量,不 用于词法变量。不是一个好主意。
【讨论】:
实际上,在 Emacs Lisp 中,没有像通过值或引用传递参数这样的事情,更不用说指针了。但是传递给函数的所有参数都将被提前评估,除了那些有' 前缀的参数。永远记住当你设置一个变量时,你总是只创建一个带有值的符号。[1]
所以如果你想在一个函数中修改一个变量的值,你需要做的就是在那个函数中修改那个变量的符号的值。
检查我的代码如下。
(defvar my-val 1)
(defun my-func-value (val)
(setq val 2))
(defun my-func-symbol (sym)
;; NOTE! using set instead of setq,
;; casue we want symbol "my-val" be evaluated from "sym" here
(set sym 2))
(my-func-value my-val) ; evaluate my-val before passed into function
(message "my-val: %s" my-val) ; my-val: 1
(my-func-symbol 'my-val) ; pass my-val symbol directly into function
(message "my-val: %s" my-val) ; my-val: 2
注意!如果该变量是词法绑定变量[2],则仍然可以修改符号的值,但不能修改词法环境中的值。
代码如下:
(let ((my-lexical-var 1))
(my-func-symbol 'my-lexical-var)
;; evaluate from lexical environment
(message "my-lexical-var: %s" my-lexical-var) ; my-lexical-var: 1
;; evaluate from the symbol
(message "symbol my-lexical-var: %s" (symbol-value 'my-lexical-var))
; symbol my-lexical-var: 2
【讨论】:
' 不是前缀,而是阅读器宏,用于缩写 quote form,其计算结果为第二项。
set(因为词法值和符号值不是一回事)。