Мне не совсем понятны все варианты локальных переменных буфера, даже после прочтения всех документов и множества публикаций здесь на SX.
Вот краткое изложение моего понимания:
(defvar foo ..)
объявляет динамическую переменную для файла. Но переменная (1) не известна другим файлам, если они не содержат также и defvar
оператор, и (2) переменная является глобальной по объему, а не локальной буферизацией.
(make-variable-buffer-local foo)
после defvar
вышесказанного сообщаем компилятору и всем остальным, что переменная foo должна рассматриваться как локальная по отношению к буферу везде, где она установлена, когда она установлена. Таким образом, этот шаблон является хорошим стилем для объявления локальной буферной переменной, помещающей оба оператора в файл.
(defvar xxx ...) ;declare xxx with global scope
(make-variable-buffer-local 'xxx) ;but now make it buffer-local everywhere
Для удобства (defvar-local xxx ...)
форму можно использовать как одну строку вместо двух строк выше:
(defvar-local xxx ...) ;make xxx buffer local everywhere
После объявления, как указано выше, переменная xxx может использоваться как любая другая переменная в операторах setq.
Если я просто хочу иметь единственный экземпляр локальной буферной переменной, которая уже является глобальной динамической переменной, я бы использовал следующие объявления. Первый объявляет динамическую переменную глобальной области видимости, а второй оператор создает только один экземпляр локальной для буфера версии этой переменной в текущем буфере:
(defvar xxx ...) ;declare xxx with global scope
(make-local-variable 'xxx) ;make xxx local in this buffer only
Теперь для моих эксплицитных вопросов (все вышеперечисленные были неявными вопросами о том, правильное ли мое понимание).
При установке значения переменных я могу использовать setq
или
setq-local
. Когда следует setq-local
использовать? Почему?
Что произойдет, если я использую setq-local
переменные локального буфера или локальные переменные без буфера?
Является ли setq-local
требуется для defvar-local
объявленной переменной?
Будет ли setq-local
обычная defvar
объявленная переменная превратить ее в локальную переменную буфера? (Другими словами, setq-local
как-то эквивалент (make-variable-local xxx)
объявления?
(setq-local VAR VALUE)
это просто сокращение(set (make-local-variable VAR) VALUE)
, которое было (и остается) общей идиомой.Ответы:
Большинство ваших предположений близки. Я упомяну несколько позже. Но сначала главный вопрос.
Форма
setq-local
- это просто удобство, это то же самое, что делать,make-local-variable
а затем следоватьsetq
. Если вы C-h f setq-localпросмотрели документацию и нажали на источник, возможно, вы видели это. Вот так я проверил свое первое впечатление. Код немного неясен, так как он оптимизирует такие вещи, как тот факт, чтоmake-local-variable
фактически возвращает саму переменную. Использованиеsetq-local
- это способ указать на локальность в некотором коде, чтобы другие знали, что код не может играть с глобальным значением переменной. Вам не нужно использовать его для доступа к локальным переменным. Любая переменная может быть сделана локальной для буфера, и это повлияет на весь код, который касается переменной (за исключением случаев, когда она делает все возможное, чтобы получить глобальную копиюsetq-default
или аналогичную).Это основной ответ. Теперь на вашем фоне есть несколько вещей, которые немного отстают. Так как вы спросили об этом, я рассмотрю некоторые вещи.
Первый «не известен другим файлам». Это не совсем правда. Любой код может ссылаться на любую глобальную переменную (поэтому они называются «глобальными»), не включая
defvar
(и C-h f defvarговорит так). Фактически, для каждой глобальной переменной должен быть только один основнойdefvar
(со строкой документации и значением по умолчанию). Аdefvar
только с именем переменной может использоваться для подавления предупреждения байтового компилятора. Emacs использует только значение из первого, которое видит, и строку документации из последнего. Если есть несколькоdefvar
s со значением / docstring, они могут ввести в заблуждение людей, читающих код. И порядок загрузки файлов будет иметь значение.Некоторые переменные предназначены для использования только в качестве локального буфера, и это те, которые используют
defvar-local
(или две частиdefvar
/ дляmake-variable-buffer-local
которых это сокращение, в основном в старом коде до добавления краткой формы). Это делает его локальным во всех буферах. Для некоторых переменных их основное использование не локально для буфера, но по какой-то причине вы можете захотеть, чтобы один буфер имел другое значение. Это когда вы используетеmake-local-variable
, как правило, в некотором буфере кода установки почти никогда сразу послеdefvar
.И вообще, у
defvar
форм есть две цели . Один из них - иметь некоторую документацию, чтобы C-h vдругие могли знать, для чего эта переменная. Второе - объявить значение «по умолчанию», чтобы переменная всегда была установлена. Объявление значения по умолчанию влияет только на глобальный (или используемый по умолчанию) экземпляр переменной и используется только в том случае, если для этого экземпляра еще ничего не установлено. Это означает, что если вы изменитеsetq
некоторую переменную, а затем включите файлdefvar
(например, через arequire
), defvar не изменит значение.¹ Точнее,
defvar
не изменяет значение переменной, если она уже установлена (однако она устанавливает строку документации); это означает, что файл инициализации пользователя может сделать(setq some-variable)
до загрузки пакета, чтобы переопределить значение по умолчанию пакета.источник
set-local
говорит читателям, что устанавливается локальная переменная. Все, что я могу сделать, чтобы улучшить читабельность моего кода, хорошо! PS. Я постараюсь чаще переходить к источнику; на моем нынешнем уровне развития, это часто не доходит до семантики ... :-)defvar
для каждой глобальной переменной» не совсем правильно - существуют ситуации, когда(defvar VARNAME)
без значения должно быть объявлено, независимо от правильного определения (с начальным значением и в идеале строкой документа) этого VARNAME.setq-local
иdefvar-local
были введены только в Emacs 24.3.(defvar varname)
следует указывать без значения? Я думаю, это то, что Дрю предложил в другой ветке, когда я спрашивал, как избавиться от предупреждений о свободных переменных в моих файлах для глобалов, которые я объявил в другом месте. Я делаю это сейчас. Это та ситуация, о которой вы говорите?C-h i g (elisp) Warning Tips
). Другой - для библиотек, использующих лексическое связывание, чтобы гарантировать (при необходимости), что переменная является динамически связанной, а не лексически связанной.