Next: ダイナミックバインディングの正しい使用, Previous: レキシカルバインディング, Up: 変数のバインディングのスコーピングルール [Contents][Index]
Local variable bindings are dynamic in the modern Lisp dialect for special variables (see below), and for all variables in the old Lisp dialect. (See Selecting Lisp Dialect.) Dynamic variable bindings have their uses but are in general more error-prone and less efficient than lexical bindings, and the compiler is less able to find mistakes in code using dynamic bindings.
When a variable is dynamically bound, its current binding at any point in the execution of the Lisp program is simply the most recently-created dynamic local binding for that symbol, or the global binding if there is no such local binding.
以下の例のように、ダイナミックバインディングはダイナミックスコープとダイナミックエクステントをもちます:
(defvar x -99) ;x
は初期値として-99を受け取る (defun getx () x) ; この関数内ではx
は自由に使用される (let ((x 1)) ;x
はダイナミックにバインドされている (getx)) ⇒ 1 ;;let
フォームが終了した後に ;;x
は前の値-99にリバートされる (getx) ⇒ -99
関数getx
はx
を参照します。defun
構文自体の中にx
にたいするバインディングが存在しないという意味において、これはフリーな参照です。x
が(ダイナミックに)バインドされているlet
フォーム内からgetx
を呼び出すと、ローカル値(つまり1)が取得されます。しかしその後let
フォームの外側からgetx
を呼び出すと、グローバル値(つまり-99)が取得されます。
以下はsetq
を使用してダイナミックに変数をバインドする例です:
(defvar x -99) ;x
は初期値として-99を受け取る (defun addx () (setq x (1+ x))) ;x
に1加算して新しい値をリターンする (let ((x 1)) (addx) (addx)) ⇒ 3 ;addx
を2回呼び出すとx
に2回加算される ;;let
フォームが終了した後に ;;x
は前の値-99にリバートされる (addx) ⇒ -98
レキシカルバインディングが有効な場合でも、特定の変数はダイナミックにバインドされたままです。これらはスペシャル変数(special
variable)と呼ばれます。defvar
、defcustom
、defconst
で定義されたすべての変数はスペシャル変数です(グローバル変数の定義を参照)。その他のすべての変数はレキシカルバインディングの対象になります。
値なしでdefvar
を使用することにより、他の場所ではレキシカルにバインドされている状態のまま、単一ファイルやファイルの一部だけで変数をダイナミックにバインドすることが可能になります。たとえば:
(let (_) (defvar x) ;x
へのletバインドはこのlet内ではダイナミック (let ((x -99)) ; これはx
のダイナミックバインド (defun get-dynamic-x () x))) (let ((x 'lexical)) ; これはx
のレキシカルバインド (defun get-lexical-x () x)) (let (_) (defvar x) (let ((x 'dynamic)) (list (get-lexical-x) (get-dynamic-x)))) ⇒ (lexical dynamic)
この関数はsymbolがスペシャル変数(つまり変数がdefvar
、defcustom
、defconst
による定義をもつ)なら非nil
をリターンする。、それ以外ならリターン値はnil
。
これは関数なので永続的にスペシャルな変数には非nil
をリターンできるが、カレントレキシカルスコープでのみスペシャルな変数では異なることに注意。
関数内の正式な引数としてのスペシャル変数の使用はサポートされていません。
Emacs Lispでのダイナミックバインディングは、シンプルな方法で実装されています。シンボルはそれぞれ、シンボルのカレントのダイナミック値(または値の不在)を指定する値セルをもちます。シンボルの構成要素を参照してください。あるシンボルがダイナミックなローカル値を与えられたとき、Emacsは値セルの内容(または値の不在)をスタックに記録して、新しいローカル値を値セルに格納します。バインディング構文が実行を終えたとき、Emacsはスタックから古い値をpopして値セルにそれを配置します。