Un obstáculo importante es que la semántica de enlace para variables indefinidas , es decir, variables no definidas con defvar
y amigos, cambia con lexical-binding
: Sin ella, lo let
une todo dinámicamente, pero con las lexical-binding
variables indefinidas habilitadas están unidas léxicamente , e incluso se eluyen completamente si no se usan en el ámbito léxico actual. .
El código antiguo a veces se basa en esto. Para evitar dependencias difíciles para las características opcionales, vincularía variables dinámicas sin requerir la biblioteca correspondiente o declarar la variable en sí:
(let ((cook-eggs-enabled t))
(cook-my-meal))
Si la función de cocción es opcional, no queremos forzar dependencias innecesarias en el usuario, por lo que no utilizamos (require 'cook)
y en su lugar confiamos en la carga automática de la cook-my-meal
función.
Es obvio para el lector humano que cook-eggs-enabled
no es una variable local, pero aún se refiere a alguna variable dinámica global de la cook
biblioteca aquí. Sin lexical-binding
este código funciona según lo previsto: cook-eggs-enabled
está vinculado dinámicamente, ya sea definido o no.
Con lexical-binding
obstante, se rompe: cook-eggs-enabled
ahora está obligado léxico (y luego optimizado de distancia, ya que no se usa), por lo que la variable dinámica mundial cook-eggs-enabled
está no siempre toca en absoluto y todavía nil
en el momento en cook-my-meal
que se llama, por lo que es sorprendente que no vamos a tener ningún huevo en nuestra comida
Afortunadamente, estos problemas son muy fáciles de detectar : el compilador de bytes advierte naturalmente sobre un enlace léxico no utilizado aquí.
La solución es simple: agregue un (require 'cook)
(para características que no son realmente opcionales de todos modos) o, para evitar dependencias difíciles, declare la variable como variable dinámica en su propio código . Hay una defvar
forma especial para esto:
(defvar cook-eggs-enabled)
Esto se define cook-eggs-enabled
como variable dinámica, pero no afecta la cadena de documentación, load-history
(y por lo tanto find-variable
y amigos) ni nada más, excepto la naturaleza de enlace de la variable.
cook-eggs-enabled
se desvincularía cuandolet
finalice? Estoy bastante seguro de que me he encontrado con un error como este antes. El defvar estaba ocurriendo dentro dellet
, y ellet
posterior restableció la variable a su estado inicial (nulo).