一千萬個為什麽

搜索

除了保存/恢復點的保存偏移的替代方案?

Q: is there an alternative to save-excursion that only saves/restores point?

在編寫elisp函數時,我經常需要保存點,在當前緩沖區中執行一些操作,然後還原點。我總是使用 save-excursion 這樣做,但docstring指出它會:

保存點,標記和當前緩沖區;執行BODY;恢復那些東西。   像 progn 一樣執行BODY。   恢復point,mark和當前緩沖區的值   即使出現異常退出(拋出或錯誤)。   標記的激活狀態也會恢復。

現在:如果我所關心的只是點而且我沒有觸及(或者不關心)標記和當前緩沖區,那似乎有些過分。在沒有像 save-point 這樣的東西的情況下,我編寫了以下宏:

(defmacro save-point (&rest body)
  (cl-declare (debug t) (indent 0))
  (let ((orig (cl-gensym)))
    `(let ((,orig (point-marker)))
       (unwind-protect
           (progn ,@body)
         (goto-char ,orig)))))

save-excursion is written in C, so it wasn't a priori clear that this macro would be faster than the C code despite saving and restoring fewer objects. And, in fact, it's about an order of magnitude slower:

(benchmark-run-compiled 1000
  (save-point t))                   ; => .0005ish

(benchmark-run-compiled 1000
  (save-excursion t))               ; => .00005ish

它目前看起來像宏是一個傻瓜的差事。所以:

  • 這樣的 save-point 宏是否已存在?
  • 如何簡化此宏以加快速度?
  • 有沒有辦法彌補C代碼和elisp代碼之間的速度差異?

最佳答案

您可以使用 letunwind-protect 自行輕松保存和恢復點。如果你願意的話,你可以把它放到你自己的宏中。但為什麽要這麽麻煩?

There is a reason that these things are saved & restored together by save-excursion. Otherwise, you had better be sure about which buffer you want to restore the value of point for etc.

My advice: use save-excursion. My guess is that it really costs nothing more than what you would code yourself to save & restore just point, and in fact will be quite a bit faster because it is coded in C.

即使 save-excursion 在Lisp中編碼,它也只是另外兩個 let 綁定,一次調用 current-buffer ,還有一個 setqset-buffer

轉載註明原文: 除了保存/恢復點的保存偏移的替代方案?