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ść f1
traktowana jest my-dynamic-var
jak 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:
defvar
Forma deklaruje również zmienną jako „Special”, tak, że zawsze jest związany dynamicznie nawet jeślilexical-binding
jest t.
Jeśli zmienię defvar
formularz 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 defvar
podczas 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)