Динамическое связывание
В современной диалектной версии Lisp локальные привязки переменных являются динамическими для специальных переменных (см. ниже), а в старой диалектной версии Lisp — для всех переменных. (См. раздел Выбор диалектной версии Lisp.) Динамические привязки переменных полезны, но в целом более подвержены ошибкам и менее эффективны, чем лексические привязки, а компилятору сложнее находить ошибки в коде, использующем динамические привязки.
Когда переменная связана динамически, её текущая привязка в любой момент выполнения программы на Lisp — это просто самая недавно созданная динамическая локальная привязка для этого символа либо глобальная привязка, если такой локальной привязки нет.
Динамические привязки имеют динамические область видимости и время жизни, что иллюстрирует следующий пример:
(defvar x -99) ;xreceives an initial value of −99. (defun getx () x) ;xis used free in this function. (let ((x 1)) ;xis dynamically bound. (getx)) ⇒ 1 ;; After theletform finishes,xreverts to its ;; previous value, which is −99. (getx) ⇒ -99
Функция getx обращается к x. Это свободное обращение в том смысле, что внутри самой конструкции defun нет привязки для x. Когда мы вызываем getx внутри формы let, в которой x связано (динамически), она получает локальное значение (то есть 1). Но когда мы вызываем getx вне формы let, она получает глобальное значение (то есть −99).
Вот ещё один пример, показывающий, как установить значение динамически связанной переменной с помощью setq:
(defvar x -99) ;xreceives an initial value of −99. (defun addx () (setq x (1+ x))) ; Add 1 toxand return its new value. (let ((x 1)) (addx) (addx)) ⇒ 3 ; The twoaddxcalls add toxtwice. ;; After theletform finishes,xreverts to its ;; previous value, which is −99. (addx) ⇒ -98
Даже если лексическое связывание включено, некоторые переменные по-прежнему будут связываться динамически. Их называют специальными переменными. Все переменные, определённые с помощью defvar, defcustom или defconst, являются специальными переменными (см. раздел Определение глобальных переменных). Ко всем остальным переменным применяется лексическое связывание.
Если использовать defvar без значения, можно связать переменную динамически только в одном файле или в одной его части, сохраняя лексическое связывание в остальных местах. Например:
(let (_) (defvar x) ; Let-bindings ofxwill be dynamic within this let. (let ((x -99)) ; This is a dynamic binding ofx. (defun get-dynamic-x () x))) (let ((x 'lexical)) ; This is a lexical binding ofx. (defun get-lexical-x () x)) (let (_) (defvar x) (let ((x 'dynamic)) (list (get-lexical-x) (get-dynamic-x)))) ⇒ (lexical dynamic)
- Функция: special-variable-p symbol
-
Эта функция возвращает значение, отличное от
nil, если symbol является специальной переменной (то есть для неё определена переменная с помощьюdefvar,defcustomилиdefconst). В противном случае возвращаемое значение —nil.Обратите внимание: поскольку это функция, она может возвращать значение, отличное от
nil, только для переменных, которые являются специальными постоянно, но не для тех, которые являются специальными лишь в текущей лексической области видимости.
Использование специальной переменной в качестве формального аргумента функции не поддерживается.
Динамическое связывание в Emacs Lisp реализовано простым способом. У каждого символа есть ячейка значения, в которой хранится его текущее динамическое значение (или указание на отсутствие значения). См. раздел Компоненты символа. Когда символу назначается динамическая локальная привязка, Emacs сохраняет содержимое ячейки значения (или отсутствие значения) в стеке, а новое локальное значение записывает в ячейку значения. Когда выполнение конструкции связывания завершается, Emacs извлекает из стека старое значение и помещает его в ячейку значения.
Copyright © 1990-1996, 1998-2026 Free Software Foundation, Inc.
Licensed under the GNU GPL license.
https://www.gnu.org/software/emacs/manual/html_node/elisp/Dynamic-Binding.html