一千萬個為什麽

搜索

條件 - 案例 - 除非 - 調試代碼研究

(defmacro condition-case-unless-debug (var bodyform &rest handlers)
  (let ((bodysym (make-symbol "body")))
    `(let ((,bodysym (lambda() ,bodyform)))
       (if debug-on-error
           (funcall ,bodysym)
         (condition-case ,var
             (funcall ,bodysym)
           ,@handlers)))))

我試圖深入研究這個宏定義,我有很多問題:

  1. This macro uses nested let blocks instead of a single let block? And doesnt the inner let block's bodysym variable always override the outer bodysym variable?

  2. How is condition-case-unless-debug different from condition-case? Sorry folks, the elisp doc is not clear enough.

  3. @handlers ---> what does @ symbol before a variable name stand for?

最佳答案

在擴展宏期間評估外部 let ;它綁定符號 bodysym 。執行結果代碼時評估內部let;它綁定一個名稱為 body 的符號。

這是一個更簡單,大多數等效的宏,它只使用符號 body

(defmacro condition-case-unless-debug (var bodyform &rest handlers)
  `(let ((body (lambda() ,bodyform)))
     (if debug-on-error
         (funcall body)
       (condition-case ,var
           (funcall body)
         ,@handlers))))

這個更簡單的宏的問題是它擴展的代碼使用符號 body 。這會幹擾 body 在使用它的地方作為變量名的使用。而不是 body ,宏可以使用像 condition-case-unless-debug/body 這樣的符號,這在其他任何地方都沒有使用,但即便如果宏也會失敗多次使用,一次嵌套在另一次。因此宏使用 make-symbol 每次展開時都會創建一個不同的符號。在編寫擴展為使用臨時變量的代碼的宏時,創建新符號是一個常見問題。

從上面的簡化版本中可以很容易地看出這個宏與普通的 condition-case 之間的區別:生成的代碼檢查變量 debug-on-error ,如果發生錯誤,而不是應用錯誤處理程序,代碼讓調試器捕獲錯誤。這在調試錯誤處理時很有用,但您不會在生產代碼中使用它。

,@ in front of a variable name is a way to expand a variable under backquotes, like , except that it treats the value of the variable as a list and splices it. Thus in (condition-case ,var (funcall body) ,@handlers) the variable handlers should contain a list of handlers; this is equivalent to (append (list 'condition-case var '(funcall body) ) handlers).

轉載註明原文: 條件 - 案例 - 除非 - 調試代碼研究