私はemacsメジャーモードを書いています。これは、バッファーローカル変数を使用していくつかの状態を格納します。
(defun foo-mode ()
"My Nice major mode"
(interactive)
(kill-all-local-variables)
(setq mode-name "foo")
(setq major-mode 'foo-mode)
(set (make-local-variable 'foo-state) "bar"))
(defun foo-change-state ()
(setq foo-state "baz"))
これは非常にうまく機能し、私のメジャーモードを使用していないバッファーではfoo-state
変数はバインドされていません(シンボルテーブルが乱雑にならないようにするため、これは私の意見では良いことです)。
ただし、このようなコードをバイトコンパイルすると、次の警告が表示されます。
Warning: assignment to free variable `foo-state'
defvar
を使用すると警告は表示されなくなりますが、foo-state
はどこにでもバインドされていますが、これは私の意見では望ましくありません。
すべてのバッファーでモード固有の変数をバインドせずに警告を取り除く方法はありますか?または、これらの変数をグローバルに宣言してはいけないと思うとき、私は間違っていますか?
あなたがやりたいことをする公式な方法は(defvar foo-state)
。 2番目の引数がないことに注意してください。また、このような宣言は、それが見つかったファイル(または関数内で使用されている場合は、見つかったスコープ)にのみ適用されることに注意してください。
変数をdefvar
で宣言します。警告を削除する方法は他にありません。これは本当に良い習慣と考えられています。
シンボルテーブルを整理するという意図は価値がありますが、実際にはそうしていません。 Emacs LISPでの変数バインディングのセマンティクスを誤解していると思います。宣言しないことで、foo-state
がfoo-mode
を使用しないバッファーでバインド解除されると信じているようです。 そうではありません。
Emacsでは、LISP名(別名シンボル)はglobalです。 foo-state
が初めて評価されるとすぐに、ランタイムはfoo-state
の新しいシンボルオブジェクトを作成し、これをグローバルシンボルテーブル(別名obarray
)に入れます。ローカルシンボルテーブルがないため、foo-state
がどこで評価され、foo-state
はsameをどのように参照するかは問題ではありません。 任意の場所のシンボルオブジェクト( シンボルの作成 を参照)。
各シンボルオブジェクトはコンポーネント(別名セル)で構成され、その1つはvariableセルです( シンボルコンポーネント を参照)。 setq
は、システムの現在のバインディングを変更します。最上位レベルでは字句バインディングは行われません。これにより、シンボルオブジェクトの変数セルが実質的に変更されます。つまり、global変数の値。繰り返しますが、setq
がどこで評価されるかは問題ではありません。実際、一部のbar-mode
が(setq foo-state "bar")
を評価した場合、foo-state
もfoo-mode
の「bar」にバインドされ、逆も同様です。
したがって、(defvar)
に対する(setq)
の唯一の効果は、シンボルをグローバル変数として使用する意図documentingであるため、他の人に伝える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にも当てはまります。