次のファイルという名前のファイルがあるとします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
れていることを示しています。ただし、最後の形式では、にvoid変数エラーが発生しmy-dynamic-var
、この変数に字句スコープが使用されていることを示しています。これは、のドキュメントと矛盾しているようですdefvar
。
また、
defvar
フォームは変数を「特別」として宣言するため、たとえlexical-binding
tであっても常に動的にバインドされます。
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)