Припустимо, у мене є файл з назвою, 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
Я завантажую цей файл, а потім заходжу в буфер нуля і запускаю:
(setq lexical-binding t)
(f1 5)
(let ((my-dynamic-var 5))
(f2))
(f1 5)
повертає 5, як очікувалося, що вказує на те, що тіло f1
розглядається my-dynamic-var
як динамічно змінена змінна, як очікувалося. Однак остання форма дає помилку змінної пустоти для my-dynamic-var
, вказуючи на те, що вона використовує лексичне визначення для цієї змінної. Це, мабуть, суперечить документації для defvar
, яка говорить:
defvar
Форма також оголошує змінну як «спеціальний», так що вона завжди динамічно пов'язана , навіть якщоlexical-binding
це т.
Якщо я зміню defvar
форму в тестовому файлі, щоб надати початкове значення, то змінна завжди трактується як динамічна, як йдеться в документації. Чи може хто-небудь пояснити, чому масштабування змінної визначається тим, чи defvar
було поставлено початкове значення при оголошенні цієї змінної?
Ось зворотний аналіз помилок, якщо це має значення:
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)