Załóżmy, że mam plik o nazwie elisp-defvar-test.el:
;;; elisp-defvar-test.el --- -*- lexical-binding: t -*-
(defvar my-dynamic-var)
(defun f1 (x)
"Should return X."
(let ((my-dynamic-var x))
(f2)))
(defun f2 ()
"Returns the current value of `my-dynamic-var'."
my-dynamic-var)
(provide 'elisp-dynamic-test)
;;; elisp-defvar-test.el ends here
Ładuję ten plik, a następnie przechodzę do bufora scratch i uruchamiam:
(setq lexical-binding t)
(f1 5)
(let ((my-dynamic-var 5))
(f2))
(f1 5)zwraca 5 zgodnie z oczekiwaniami, co wskazuje, że treść f1traktowana jest my-dynamic-varjak zmienna o dynamicznym zasięgu, zgodnie z oczekiwaniami. Jednak ostatnia forma podaje błąd zmiennej void dla my-dynamic-var, wskazując, że używa ona leksykalnego zakresu dla tej zmiennej. Wydaje się to sprzeczne z dokumentacją defvar, która mówi:
defvarForma deklaruje również zmienną jako „Special”, tak, że zawsze jest związany dynamicznie nawet jeślilexical-bindingjest t.
Jeśli zmienię defvarformularz w pliku testowym, aby podać wartość początkową, zmienna jest zawsze traktowana jako dynamiczna, jak głosi dokumentacja. Czy ktoś może wyjaśnić, dlaczego zakres zmiennej zależy od tego, czy defvarpodczas deklarowania tej zmiennej podano wartość początkową?
Oto ślad śledzenia błędu, na wypadek, gdyby miał on znaczenie:
Debugger entered--Lisp error: (void-variable my-dynamic-var)
f2()
(let ((my-dynamic-var 5)) (f2))
(progn (let ((my-dynamic-var 5)) (f2)))
eval((progn (let ((my-dynamic-var 5)) (f2))) t)
elisp--eval-last-sexp(t)
eval-last-sexp(t)
eval-print-last-sexp(nil)
funcall-interactively(eval-print-last-sexp nil)
call-interactively(eval-print-last-sexp nil nil)
command-execute(eval-print-last-sexp)