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 defvarvà bạn bè thay đổi với lexical-binding: Nếu không có nó, letliên kết mọi sự năng động, nhưng với lexical-bindingcá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-mealchức năng.
Rõ ràng đối với người đọc cook-eggs-enabledkhô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ừ cookthư viện ở đây. Không có lexical-bindingmã này hoạt động như dự định: cook-eggs-enabledbị ràng buộc động, cho dù được xác định hay không.
Với lexical-bindingtuy nhiên, nó phá vỡ: cook-eggs-enabledhiệ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-enabledlà 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 defvarhình thức đặc biệt cho việc này:
(defvar cook-eggs-enabled)
Điều này định nghĩa cook-eggs-enabledlà biến động, nhưng không ảnh hưởng đến chuỗi doc, load-history(và do đó find-variablevà 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 khiletkế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 trongletvàletsau đó khôi phục biến về trạng thái ban đầu (void).