elisp中如何将变量当作参数传给一个函数

(setq x nil)


(defun foo (var)
  (if t
      (setq var 1)
    (setq var -1))
  )

上面x是在foo函数外部定义的一个变量, 希望foo函数中,可以对其进行修改

执行(funcall 'foo x) x好像没变呀

(setq x nil)

(defun foo (var)
  (if t (set var 1) (set var -1)))

x ; nil

(foo 'x)

x ; 1

setq 是宏,你的 foo 去掉 var 参数也能跑

我这里咋不对呀

我这里只是模拟,实际是在let里面的定义的一个var,然后想在后面的函数中赋值

(let (var)
   (foo var))

类似这样

注意到我用 set 替换掉了 setq

在这个场景下

(setq var 1) 

宏展开后变为

(set 'var 1)

不会去读 var 里面是什么

1 个赞

如果开启了lexical-binding,实际上是无法把变量传给函数的。

;; -*- lexical-binding: t; -*-

(defun foo (var)
  (if t
      (set var 1)
    (set var -1)))

(let ((x 0))
  (foo 'x)
  x) ; 结果还是 0

可行的方法是传一个cons,再函数里面修改cons cell的值。

(defun foo2 (cell)
   (if t
     (setcar cell 1)
    (setcar cell -1)))

(let ((x (list 0)))
  (foo2 x)
  (car x)) ;; 1

如果想要修改变量里面的内容,那最好是传递列表或向量,它们是引用值而不是立即值,修改这些数据内部的内容是可行的:

(defun my-set (x val) (setcar x val))

(let ((x (list 1)))
  (my-set x 2)
  x)
=> 2

另外, gv.el 提供了一个通用的引用和解引用操作,在词法作用域下可以这样做:

(defun my-set2 (x val)
  (setf (gv-deref x) val))

(let ((x 1))
  (my-set2 (gv-ref x) 30)
  x)
=> 30