在Elisp中,参数如何传递给函数?

6

作为一名有C++背景的开发者,我正试图弄清楚Elisp中方法参数是如何传递的。虽然措辞可能不同,但我想知道它是否更接近于C++中的按引用传递或按值传递的概念?如果我在方法中修改参数,它会改变在函数调用中传入的参数吗?

2个回答

10

所有的Lisp(Emacs LispCommon 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 - 它接受一个符号(变量名)并修改其值。这仅适用于全局动态变量,而不适用于词法变量。这不是一个很好的想法。


2
实际上,在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

2
所有函数参数都会被评估。 ' 不是前缀,而是一个读取宏,用于缩写 引用形式,该形式评估为其第二个术语。 - sds
是的,我知道它是一个引用表单,但也像那个变量的前缀。无论如何,你没有抓住重点。你有看过我上面的代码片段吗?那就是我想指出的东西。@sds - Francis
请注意,如果变量具有词法作用域(这在此处不是情况),那么传递变量的符号并不能让您使用set修改变量的值(因为词法值和符号值并不相同)。 - phils

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接