Một cái bẫy chính là ngữ nghĩa bắt buộc đối với xác định các biến biến-tức là không được định nghĩa với defvar
và bạn bè thay đổi với lexical-binding
: Nếu không có nó, let
liên kết mọi sự năng động, nhưng với lexical-binding
các biến không xác định được kích hoạt đang bị ràng buộc lexically , và thậm chí elided hoàn toàn nếu không sử dụng trong phạm vi từ vựng hiện tại .
Mã cũ đôi khi dựa vào điều này. Để tránh phụ thuộc cứng cho các tính năng tùy chọn, nó liên kết các biến động mà không yêu cầu thư viện tương ứng hoặc tự khai báo biến đó:
(let ((cook-eggs-enabled t))
(cook-my-meal))
Nếu tính năng nấu là tùy chọn, chúng tôi không muốn buộc các phụ thuộc không cần thiết vào người dùng, vì vậy chúng tôi không sử dụng (require 'cook)
và thay vào đó dựa vào tự động tải cook-my-meal
chức năng.
Rõ ràng đối với người đọc cook-eggs-enabled
không phải là biến cục bộ, nhưng vẫn đề cập đến một số biến động toàn cầu từ cook
thư viện ở đây. Không có lexical-binding
mã này hoạt động như dự định: cook-eggs-enabled
bị ràng buộc động, cho dù được xác định hay không.
Với lexical-binding
tuy nhiên, nó phá vỡ: cook-eggs-enabled
hiện đang bị ràng buộc lexically (và sau đó tối ưu hóa đi, bởi vì nó không được sử dụng), do biến động toàn cầu cook-eggs-enabled
là không bao giờ chạm chút nào và vẫn nil
do thời gian cook-my-meal
được gọi, vì vậy chúng tôi ngạc nhiên sẽ không có bất kỳ trứng trong bữa ăn của chúng tôi
May mắn thay, những vấn đề này rất dễ phát hiện : Trình biên dịch byte cảnh báo một cách tự nhiên về một ràng buộc từ vựng không sử dụng ở đây.
Cách khắc phục rất đơn giản: Hoặc thêm một (require 'cook)
(đối với các tính năng không thực sự là tùy chọn nào), hoặc để tránh phụ thuộc cứng, khai báo biến là biến động trong mã của riêng bạn . Có một defvar
hình thức đặc biệt cho việc này:
(defvar cook-eggs-enabled)
Điều này định nghĩa cook-eggs-enabled
là biến động, nhưng không ảnh hưởng đến chuỗi doc, load-history
(và do đó find-variable
và bạn bè) hoặc bất cứ điều gì khác, ngoại trừ bản chất ràng buộc của biến.
cook-eggs-enabled
được cởi ra khilet
kết thúc? Tôi khá chắc chắn rằng tôi đã gặp phải một lỗi như thế này trước đây. Defvar đã xảy ra bên tronglet
vàlet
sau đó khôi phục biến về trạng thái ban đầu (void).