Giá trị mặc định của biến đệm cục bộ không được đặt cho đến khi `setq` đầu tiên


7

Giả sử tôi xác định biến cục bộ đệm foovà giá trị mặc định của nó là "a":

(defvar foo "a")
(make-variable-buffer-local 'foo)
(default-value 'foo) ;; => "a"

Ngay sau đó tôi chạy đoạn mã sau:

(let ((foo "b"))
  (with-temp-buffer
    (message "foo: %s" foo))) ;; => "b"

Kết quả là "b", là giá trị tôi đặt let.

Bây giờ nếu tôi sử dụng setqđể đặt biến, thì hãy chạy lại mã chính xác như trước:

(setq foo "c") ;; => "c"

(let ((foo "b"))
  (with-temp-buffer
    (message "foo: %s" foo))) ;; => "a"

Kết quả là "a", là giá trị mặc định bây giờ.

Câu hỏi : đối với bộ đệm tạm thời, giá trị mặc định của fookhông được đặt cho đến khi tôi sử dụng setq? Và miễn là tôi không sử dụng setq, tôi có thể sử dụng letđể thay đổi giá trị mặc định trong các bộ đệm khác không?

EDIT : như @npostavs đã nói, đây là những gì make-varible-buffer-localthực sự có nghĩa. Nếu tôi sử dụng make-variable-buffer-localbản thân, tôi luôn có thể sử dụng setqsau đó. Nhưng điều này thực sự trở nên khó khăn đối với các biến cục bộ đệm "tích hợp" như thế nào case-fold-search. nếu tôi, với tư cách là một tác giả gói, liên kết case-fold-searchvới nilbên ngoài letvà tôi muốn sử dụng giá trị mặc định (nó có thể hoặc không được người dùng đặt) trong with-temp-buffer, tôi phải sử dụng setqtrước with-temp-bufferđể đảm bảo giá trị mặc định thực sự được sử dụng trong trường hợp người dùng không có nó setqtrong đó init.el. Đối với các biến cục bộ đệm, điều đó có nghĩa setqlà luôn an toàn hơn so với letkhi chúng ta muốn đặt giá trị. Tôi tự hỏi liệu thiết kế hoặc tài liệu có thể được cải thiện.


Nếu bạn đặt phần giới hạn bên trong cơ thể của with-temp-buffer(thay vì trước đó), điều đó có giúp ích gì không? with-temp-bufferlà một macro và nó hoạt động hơi khác so với một chức năng tiêu chuẩn. Ví dụ:(with-temp-buffer (let ((foo "b")) (message "foo: %s" foo)))
luật

@lawlist Điều đó sẽ làm việc như mong đợi, mà tôi hiểu. Nhưng tôi không thể tìm thấy bất kỳ tài liệu nào giải thích ví dụ tôi đã nói trong câu hỏi.
cutejumper

Tôi có thể đặt câu hỏi - Làm cách nào tôi có thể thâm nhập vào phần cơ thể của macro bằng một biến bị ràng buộc trước đó (ví dụ: với cách tiếp cận back-tick / dấu phẩy, hoặc từ vựng, hoặc có lẽ là thứ gì khác)? ... Nhưng, tôi không muốn chiếm đoạt câu hỏi của bạn ... một người thích vĩ mô sẽ sớm xuất hiện để giải thích tất cả ... :)
luật

1
@lawlist Tôi không biết liệu điều này có liên quan đến macro hay không. Tôi thực sự kiểm tra nó cục bộ bằng cách sử dụng hình thức mở rộng with-temp-buffer(có nghĩa là, không có macro). Tôi nghĩ nó giống như một hành vi cụ thể cho các biến đệm cục bộ.
cutejumper

Câu trả lời:


6

Tôi, với tư cách là một tác giả gói, liên kết case-fold-searchvới nilbên ngoài cho phép và tôi muốn sử dụng giá trị mặc định (người dùng có thể hoặc không thể đặt nó) trong with-temp-buffer,

Trong trường hợp này tôi muốn giới thiệu

(let ((case-fold-search (progn (make-local-variable 'case-fold-search)
                               nil)))
  (with-temp-buffer
    ...))

Điều quan trọng cần lưu ý ở đây là make-variable-buffer-localkhông tạo bộ đệm biến cục bộ! Nó chỉ sắp xếp để nó trở thành vùng đệm sau khi được đặt . Bạn có thể muốn sử dụng make-local-variablethay thế.

(make-variable-buffer-local VARIABLE)

Make VARIABLE become buffer-local whenever it is set.

Điều thứ hai cần lưu ý là sự tương tác của letvới các biến đệm cục bộ, từ (elisp) Intro to Buffer-Local:

Cảnh báo: Khi một biến có các ràng buộc cục bộ đệm trong một hoặc nhiều bộ đệm, hãy khởi động letlại các ràng buộc hiện đang có hiệu lực. Ví dụ, nếu bộ đệm hiện tại có giá trị bộ đệm cục bộ, let tạm thời sẽ phản hồi lại. Nếu không có ràng buộc cục bộ đệm nào có hiệu lực, hãy khởi động letlại giá trị mặc định.

Vì vậy, trong trường hợp đầu tiên bạn ràng buộc giá trị toàn cầu để "b"và cho thấy trong bộ đệm tạm thời. Trong trường hợp thứ hai, sau khi bạn đã đặt giá trị cục bộ *scratch*thành "c", sau đó bạn liên kết giá trị cục bộ thành "b", nhưng các bộ đệm khác vẫn thấy giá trị toàn cục của "a".


Tôi đoán tôi đã hiểu nhầm câu Make VARIABLE become buffer-local whenever it is set.. Tôi nghĩ rằng nó đã nói bất cứ khi nào chúng ta đặt giá trị, chỉ có giá trị bộ đệm cục bộ được đặt. Vì vậy, để tránh một vấn đề như vậy, có lẽ chúng ta nên luôn luôn sử dụng setqngay sau đó make-variable-buffer-local?
cutejumper

Tôi thực sự gặp phải vấn đề này đối với các bộ đệm cục bộ "tích hợp" như case-fold-searchfill-column. Bản thân Emacs không đặt chúng sau khi nó xác định các biến cục bộ đệm này và nó yêu cầu người dùng đặt chúng để làm cho chúng thực sự đệm cục bộ. Là thiết kế này có chủ ý? Tôi không nghĩ rằng hầu hết mọi người nhận thức được điều này.
cutejumper

Yêu cầu người dùng sử dụng make-local-variablehoặc setqtrong khi nó nói biến này là bộ đệm - cục bộ thực sự khó hiểu. Nhưng có lẽ đó là một câu hỏi khác liên quan đến thiết kế.
cutejumper

Chà, nếu nó được tạo ngay bộ đệm cục bộ, thì câu hỏi sẽ là làm thế nào để liên kết giá trị mặc định ...
npostavs

Cảm ơn. Tôi vẫn cảm thấy kỳ lạ make-local-variablekhi sử dụng khi tôi thấy biến đã "đệm cục bộ" từ hướng dẫn. Tôi hy vọng letcó thể liên kết các bản sao đệm cục bộ. Nhưng điều này có thể phù hợp hơn để được hỏi trong Emacs-devel.
cutejumper

0

Giống như giải pháp đề xuất của bạn, chúng tôi có thể liên kết nó với một biến tùy ý bên trong let, sau đó thay đổi theo ý muốn trong khi vẫn ở bên trong let, trước khi quay trở lại giá trị ban đầu.

Vấn đề phát sinh khi thay đổi bộ đệm bên trong let- do phạm vi động, giá trị của các biến cục bộ sẽ không 'chuyển sang' vào bộ đệm mới, ngay cả khi bên trong lexical-let.

Đây là một hàm kiểm tra vấn đề này, đồng thời thiết lập và hoàn nguyên giá trị mặc định, là giá trị được sử dụng bởi bộ đệm tạm thời:

(defun f1 (VAR TEMP-VALUE) "
Sets VAR to TEMP-VALUE; works with local variables also." 
   (interactive)
   ;; starting value
   (insert (prin1-to-string VAR))
   (let ((var1 VAR))
     (setq VAR TEMP-VALUE)
     (when (local-variable-p 'VAR)
       (setq-default VAR TEMP-VALUE))
     ;; current buffer-local value
     (insert (prin1-to-string VAR))
     ;; value in new buffer
     (with-temp-buffer
       (message (prin1-to-string VAR)))
     ;; back to current buffer - unchanged
     (insert (prin1-to-string VAR))
     ;; revert
     (setq VAR var1)
     (when (local-variable-p 'VAR)
       (setq-default VAR var1))
   ;; back to original value
   (insert (prin1-to-string VAR)))
   ;; exit let and re-check
   (insert (prin1-to-string VAR)))

sau đó

(f1 case-fold-search "xyz") --> t"xyz""xyz"tt

và "xyz" sẽ xuất hiện trong *Messages*bộ đệm.

Các biến cục bộ khác xuất hiện trong bối cảnh này là default-directoryuniquify-managed...

Nói tóm lại, bạn có thể định nghĩa một hàm như thế này và sử dụng nó bên trong let, vì vậy hãy lưu lại rắc rối kiểm tra xem biến (ký hiệu) có cục bộ hay không:

(defun set-ld (SYM VAL) "set local (and default if applicable)"
       (interactive)
       (setq SYM VAL)
       (when (local-variable-p 'SYM)
     (setq-default SYM VAL)))
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.