自己试了一下 loop.el 的 loop-for-each
(loop-for-each x (list 2 3)
(if (eq x 2)
(print x))
)
但我想要 同时遍历 list 的索引和值 且支持 break , continue ,return
更像 JavaScript 的
for (const [key ,value] of list){}
自己试了一下 loop.el 的 loop-for-each
(loop-for-each x (list 2 3)
(if (eq x 2)
(print x))
)
但我想要 同时遍历 list 的索引和值 且支持 break , continue ,return
更像 JavaScript 的
for (const [key ,value] of list){}
第一个问题:同时遍历 list 的索引和值可以使用 cl-loop (参见 (info “(cl) Loop Facility”))
(cl-loop for i from 0
for x in '(a b c)
collect (cons i x))
后面几个问题:一般来说,写 Emacs Lisp 会倾向于函数式风格,用到 break continue return 的几率大大小于在 C, JS 等语言。(注意 cl-loop
本身可以求出一个值,与 for
语句不同。)
如果用到了,可以使用 cl-loop 的 return
(退出循环而非函数), if
/when
等语句,见 (info “(cl) Other Clauses”)。
break 和 return 也可以用 non-local exit :catch
和 throw
。
continue 似乎没有比较直接的对应,不过这个问题也不是很大。重申一遍,用函数式风格写代码,对这种控制流的要求会低很多。
這种宏自已隨便写写拉
(defmacro iter-list (index-var element-var list &rest body)
(let ((rest (gensym))
(atag (gensym))
(btag (gensym)))
`(cl-flet ((break () (throw (quote ,atag) nil))
(return (x) (throw (quote ,atag) x))
(continue () (throw (quote ,btag) nil)))
(catch (quote ,atag)
(cl-do* ((,index-var 0 (1+ ,index-var))
(,rest ,list (cdr ,rest))
(,element-var (car ,rest) (car ,rest)))
((null ,rest))
(catch (quote ,btag)
,@body))))))
(iter-list i x '(a b c)
(if (= i 1)
(return x)))
b
(iter-list i x '(a b c)
(if (eq x 'b)
(continue)
(princ (format "is:%s\n" x))))
is:a
is:c
nil
(iter-list i x '(a b c)
(if (= i 1)
(princ (format "is:%s\n" x))))
is:b
nil
不介意 quote hell 的话可以再改进一下。
(defmacro iter-list (index-var element-var list &rest body)
(let ((rest (gensym))
(atag (gensym))
(btag (gensym)))
`(cl-macrolet ((break () (list 'throw '',atag nil))
(return (x) (list 'throw '',atag x))
(continue () (list 'throw '',btag nil)))
(catch ',atag
(cl-do* ((,index-var 0 (1+ ,index-var))
(,rest ,list (cdr ,rest))
(,element-var (car ,rest) (car ,rest)))
((null ,rest))
(catch ',btag
,@body))))))
这种宏还看不明白的