Un importante trabocchetto è che la semantica vincolanti per non definite le variabili variabili-vale a dire non definiti con defvar
gli amici-cambio con lexical-binding
: Senza di esso, let
il vincolo in modo dinamico, ma con lexical-binding
le variabili non definite abilitati sono tenuti lessicalmente , e anche completamente elise se non utilizzato nella corrente scope lessicale .
Il vecchio codice a volte si basa su questo. Per evitare forti dipendenze per le funzionalità opzionali, assocerebbe le variabili dinamiche senza richiedere la libreria corrispondente o dichiarare la variabile stessa:
(let ((cook-eggs-enabled t))
(cook-my-meal))
Se la funzione di cottura è opzionale, non vogliamo imporre dipendenze non necessarie all'utente, quindi non utilizziamo (require 'cook)
e facciamo affidamento sul caricamento automatico della cook-my-meal
funzione.
È ovvio per il lettore umano che cook-eggs-enabled
non è una variabile locale, ma fa ancora riferimento a qualche variabile dinamica globale della cook
libreria qui. Senza lexical-binding
questo codice funziona come previsto: cook-eggs-enabled
è associato in modo dinamico, definito o no.
Con lexical-binding
però, si rompe: cook-eggs-enabled
è ora legata lessicale (e poi ottimizzata via, perché non è utilizzato), quindi la variabile dinamica globale cook-eggs-enabled
è non mai toccato a tutti e ancora nil
per il momento cook-my-meal
si chiama, in modo che sorprendentemente non avrà alcun uova nel nostro pasto.
Fortunatamente, questi problemi sono molto facili da individuare : il compilatore di byte avverte naturalmente di un legame lessicale inutilizzato qui.
La correzione è semplice: aggiungi un (require 'cook)
(per le funzionalità che non sono comunque facoltative) o, per evitare dipendenze difficili, dichiara la variabile come variabile dinamica nel tuo codice . Esiste un defvar
modulo speciale per questo:
(defvar cook-eggs-enabled)
Questo definisce cook-eggs-enabled
una variabile dinamica, ma non influenza il docstring, il load-history
(e quindi gli find-variable
amici) o qualsiasi altra cosa, tranne la natura vincolante della variabile.
cook-eggs-enabled
di essere non legato quandolet
finiture? Sono abbastanza sicuro di essermi imbattuto in un bug come questo prima. La defvar stava accadendo all'interno dilet
, elet
successivamente ripristinò la variabile al suo stato iniziale (vuoto).