Un importante trabocchetto è che la semantica vincolanti per non definite le variabili variabili-vale a dire non definiti con defvargli amici-cambio con lexical-binding: Senza di esso, letil vincolo in modo dinamico, ma con lexical-bindingle 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-mealfunzione.
È ovvio per il lettore umano che cook-eggs-enablednon è una variabile locale, ma fa ancora riferimento a qualche variabile dinamica globale della cooklibreria qui. Senza lexical-bindingquesto codice funziona come previsto: cook-eggs-enabledè associato in modo dinamico, definito o no.
Con lexical-bindingperò, 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 nilper il momento cook-my-mealsi 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 defvarmodulo speciale per questo:
(defvar cook-eggs-enabled)
Questo definisce cook-eggs-enableduna variabile dinamica, ma non influenza il docstring, il load-history(e quindi gli find-variableamici) o qualsiasi altra cosa, tranne la natura vincolante della variabile.
cook-eggs-enableddi essere non legato quandoletfiniture? Sono abbastanza sicuro di essermi imbattuto in un bug come questo prima. La defvar stava accadendo all'interno dilet, eletsuccessivamente ripristinò la variabile al suo stato iniziale (vuoto).