`Setq-local` làm gì và khi nào tôi nên sử dụng nó?


16

Tôi không rõ lắm về tất cả các biến thể của các biến cục bộ đệm, ngay cả sau khi đọc tất cả tài liệu và một loạt các bài đăng ở đây trên SX.

Dưới đây là tóm tắt những hiểu biết của tôi:

(defvar foo ..)khai báo một biến động cho tập tin Nhưng biến là (1) không được biết đến với các tệp khác trừ khi chúng cũng bao gồm một defvar câu lệnh và (2) biến là phạm vi toàn cầu, không phải là bộ đệm cục bộ.

(make-variable-buffer-local foo)sau phần defvartrên cho trình biên dịch và mọi người khác biết rằng biến foo sẽ được coi là bộ đệm cục bộ ở mọi nơi nó được đặt, khi nó được đặt. Vì vậy, mẫu này là phong cách tốt để khai báo một biến bộ đệm cục bộ, đặt cả hai câu lệnh back-to-back trong tệp.

(defvar xxx ...)                    ;declare xxx with global scope
(make-variable-buffer-local 'xxx)   ;but now make it buffer-local everywhere

Để thuận tiện, (defvar-local xxx ...)mẫu có thể được sử dụng dưới dạng một dòng, thay cho hai dòng trên:

(defvar-local xxx ...)       ;make xxx buffer local everywhere

Khi được khai báo như trên, biến xxx có thể được sử dụng như bất kỳ biến nào khác trong các câu lệnh setq.

Nếu tôi chỉ muốn có một phiên bản duy nhất của biến đệm cục bộ đã là biến động toàn cục, tôi sẽ sử dụng các khai báo sau. Biến thứ nhất khai báo biến động phạm vi toàn cầu và câu lệnh thứ hai chỉ tạo một phiên bản của phiên bản đệm cục bộ của biến đó, trong bộ đệm hiện tại:

(defvar xxx ...)             ;declare xxx with global scope
(make-local-variable 'xxx)   ;make xxx local in this buffer only

Bây giờ cho các câu hỏi khám phá của tôi (tất cả các câu hỏi trên là những câu hỏi ngầm về việc sự hiểu biết của tôi có đúng không).

Khi đặt giá trị của các biến, tôi có thể sử dụng setqhoặc setq-local. Khi nào nên setq-localsử dụng? Tại sao?

Điều gì xảy ra nếu tôi sử dụng setq-localtrên các vars đệm cục bộ, hoặc các vars không đệm cục bộ?

Được setq-localyêu cầu cho một defvar-localbiến khai báo?

Liệu setq-localmột defvarbiến được khai báo bình thường có biến nó thành một biến cục bộ không? (Nói cách khác, setq-localbằng cách nào đó có tương đương với một (make-variable-local xxx)tuyên bố?


Cảm ơn vì Scott đã lao động thêm. Tôi sẽ đưa vào các backquote bổ sung từ đây trở đi.
Kevin

2
(setq-local VAR VALUE)chỉ là viết tắt cho (set (make-local-variable VAR) VALUE), mà (và vẫn là) một thành ngữ phổ biến.
Drew

Câu trả lời:


18

Hầu hết các giả định của bạn là gần gũi. Tôi sẽ đề cập một vài điều sau. Nhưng, đầu tiên câu hỏi chính.

Các hình thức setq-localchỉ là một sự thuận tiện, nó cũng giống như làm make-local-variabletheo setq. Nếu bạn đã thực hiện C-h f setq-localđể xem tài liệu và nhấp qua nguồn bạn có thể đã thấy điều này. Đó là cách tôi xác minh ấn tượng đầu tiên của mình. Tuy nhiên, mã này hơi tối nghĩa vì nó tối ưu hóa những thứ như thực tế make-local-variabletrả về chính biến đó. Sử dụng setq-locallà một cách để chỉ ra tính cục bộ trong một số mã, để những người khác biết mã không thể chơi với giá trị toàn cầu của biến. Bạn không cần sử dụng nó để truy cập các biến cục bộ. Bất kỳ biến nào cũng có thể được tạo thành bộ đệm cục bộ và điều đó sẽ ảnh hưởng đến tất cả các mã chạm vào biến đó (trừ khi nó đi ra ngoài để có được bản sao toàn cầu có setq-defaulthoặc tương tự).

Đó là câu trả lời chính. Bây giờ, có một vài điều trong nền của bạn là một chút. Vì bạn đã hỏi về điều đó, tôi sẽ giải quyết một số điều.

Đầu tiên là "không biết đến các tập tin khác". Điều này không thực sự đúng. Bất kỳ mã nào cũng có thể tham chiếu bất kỳ biến toàn cục nào (đó là lý do tại sao chúng được gọi là "toàn cầu") mà không bao gồm defvar(và C-h f defvarnói như vậy). Trong thực tế, chỉ nên có một chính defvar(với chuỗi giá trị và giá trị mặc định) cho mỗi biến toàn cục. Một defvarchỉ với tên biến có thể được sử dụng để chặn cảnh báo trình biên dịch byte. Emacs chỉ sử dụng giá trị từ cái đầu tiên mà nó nhìn thấy và chuỗi doc từ cái cuối cùng. Nếu có nhiều defvars có giá trị / chuỗi, chúng có thể gây nhầm lẫn cho những người đọc mã. Và thứ tự tải tập tin sẽ có vấn đề.

Một số biến được dự định chỉ được sử dụng làm bộ đệm cục bộ và đó là những biến được sử dụng defvar-local(hoặc hai phần defvar/ make-variable-buffer-localđược viết tắt, chủ yếu là trong mã cũ trước khi hình thức ngắn được thêm vào). Điều này làm cho nó là bộ đệm cục bộ trong tất cả các bộ đệm. Đối với một số biến, việc sử dụng chính của chúng không phải là bộ đệm cục bộ, nhưng vì một số lý do, bạn có thể muốn một bộ đệm có giá trị khác. Đó là khi bạn sử dụng make-local-variable, thông thường trong một số mã thiết lập bộ đệm hầu như không bao giờ đúng sau một defvar.

Và như một điều chung, có hai mục đích cho các defvarhình thức. Một là có một số tài liệu, để người khác C-h vcó thể sử dụng để biết biến đó dùng để làm gì. Thứ hai là khai báo một giá trị "mặc định", để biến luôn được đặt. Việc khai báo giá trị mặc định chỉ ảnh hưởng đến thể hiện toàn cầu (hoặc mặc định) của một biến và chỉ được sử dụng nếu thể hiện đó chưa được đặt thành một cái gì đó. Điều đó có nghĩa là nếu bạn có setqmột số biến và sau đó bao gồm tệp với defvar(ví dụ thông qua a require), defvar sẽ không thay đổi giá trị.

¹ Chính xác hơn, defvarkhông thay đổi giá trị của biến nếu nó đã được thiết lập (nó thiết lập các docstring tuy nhiên); điều này có nghĩa là để tệp init của người dùng có thể thực hiện (setq some-variable)trước khi gói được tải để ghi đè giá trị mặc định của gói.


1
Cảm ơn câu trả lời rất rõ ràng, nó giúp rất nhiều. Khi tôi sử dụng cụm từ "không biết đến các tệp khác", tôi đã nghĩ đến các cảnh báo biến miễn phí vì các tệp khác đó sẽ nghĩ biến đó là miễn phí trừ khi tôi cũng thêm một defvar cho chúng. Tôi thích tuyên bố của bạn set-localnói với độc giả rằng một var cục bộ đang được thiết lập. Bất cứ điều gì tôi có thể làm để cải thiện khả năng đọc mã của tôi là tốt! Tái bút Tôi sẽ cố gắng nhấp qua nguồn thường xuyên hơn; ở cấp độ phát triển hiện tại của tôi, nó thường không thực sự đạt được ở ngữ nghĩa ... :-)
Kevin

1
"chỉ nên có một biến defvarcho mỗi biến toàn cục" không đúng hoàn toàn - có những tình huống khi (defvar VARNAME) không có giá trị được khai báo, độc lập với định nghĩa đúng (với giá trị ban đầu và lý tưởng là một chuỗi) của VARNAME đó.
phils

2
Cũng lưu ý rằng setq-localdefvar-localchỉ được giới thiệu trong Emacs 24.3.
phils

1
@phils, bạn có thể vui lòng xác định các tình huống mà bạn nói đến, (defvar varname)nên khai báo ở đâu mà không có giá trị? Tôi nghĩ đó là những gì Drew đã đề xuất trong một chủ đề khác khi tôi hỏi làm thế nào để loại bỏ các cảnh báo biến miễn phí trong các tệp của tôi cho toàn cầu mà tôi đã tuyên bố ở nơi khác. Tôi làm điều đó bây giờ. Đó có phải là tình huống mà bạn nói đến?
Kevin

1
Tránh các cảnh báo biên dịch byte là một lý do, có (xem C-h i g (elisp) Warning Tips). Khác là cho các thư viện sử dụng ràng buộc từ vựng, để đảm bảo (nếu cần) rằng một biến được ràng buộc động chứ không phải ràng buộc từ vựng.
phils
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.