Объявите переменную с помощью defvar
. Нет другого способа удалить предупреждение, и это действительно считается хорошей практикой.
Ваше намерение не загромождать таблицу символов оправдано, но на самом деле вы этого не делаете. Я думаю, вы неправильно поняли семантику связывания переменных в Emacs Lisp, поскольку вы, кажется, полагаете, что, не объявляя его, foo-state
будет несвязанным в любом буфере, не использующем foo-mode
. Это не так.
В Emacs Lisp имена (они же символы) являются глобальными. Как только foo-state
оценивается в первый раз, среда выполнения создает новый объект символа для foo-state
и помещает его в глобальную таблицу символов (также известную как obarray
). Локальных таблиц символов нет, поэтому не имеет значения, где и как оценивается foo-state
, foo-state
ссылается на один и тот же объект символа в любом месте (см. Создание символов).
Каждый объект символа состоит из компонентов (ячеек), одним из которых является ячейка переменная (см. Компоненты символов). setq
изменяет текущую привязку системы, на верхнем уровне без лексической привязки это эффективно изменяет ячейку переменной объекта символа, таким образом, глобальное значение переменной. Опять же, не имеет значения, где оценивается setq
. На самом деле, если бы какое-то bar-mode
оценивало (setq foo-state "bar")
, foo-state
тоже было бы привязано к "бару" в foo-mode
, и наоборот.
Таким образом, единственный эффект (defvar)
по сравнению с (setq)
состоит в том, что документирует намерение использовать символ как глобальную переменную, то есть говорит другим не изменять эту переменную, если только не предполагается манипулирование поведением foo-mode
. Вы можете прикрепить документацию к переменной и пометить ее как определенную в своем буфере (C-h v foo-state
предоставит ссылку для перехода к определению).
Поскольку Emacs Lisp не имеет пространств имен и по умолчанию имеет динамическую область действия, документация крайне важна, чтобы избежать конфликтов между модулями. Если бы я написал bar-mode
, используя ваш foo-mode
, я мог бы случайно привязаться к foo-state
, вызвать foo-change-state
, а затем увидеть, что мой режим ведет себя неправильно, потому что переменная была непреднамеренно перезаписана. Объявление foo-state
не делает это невозможным, но, по крайней мере, позволяет мне поймать ошибку, потому что C-h v foo-state
покажет, что эта переменная используется другим режимом, поэтому мне лучше не использовать ее, если я действительно не собираюсь манипулировать этим режимом.
В качестве последнего слова: во всем вышеупомянутом тексте «режим» можно заменить файлами Emacs Lisp. modes
ничего особенного в отношении символов. Все вышесказанное справедливо и для Emacs Lisp, который не объявляет режимы, а просто содержит набор функций.
person
lunaryorn
schedule
14.09.2012
C-h i g (elisp) Warning Tips RET
- это место, где живет документация, отвечающая на этот вопрос. - person phils   schedule 08.04.2014define-derived-mode
, как в(define-derived-mode foo-mode nil "foo" "My nice major mode." (set (make-local-variable 'foo-state) "bar"))
. - person Stefan   schedule 16.04.2014Warning Tips
в Руководстве по Emacs содержит вопиющую ложь относительноdefvar
: такое определение не имеет никакого эффекта, кроме указания компилятору не предупреждать об использовании переменной [...] в этом файле. Это, безусловно, может иметь большее влияние чем просто заставить компилятор замолчать: [он] также объявляет переменную как специальную, так что она всегда динамически связывается, даже если «лексическое связывание» равно t. (цитата взята из фактической документации дляdefvar
). Возможно, совет вWarning Tips
был написан до введения лексического связывания в Emacs Lisp... - person ack   schedule 01.03.2018