Hatena::ブログ(Diary)

【はてな】ガットポンポコ RSSフィード


2009-05-08

Emacs ローカル変数

emacsでのローカル変数についてのまとめ

バッファローカル変数

バッファ内でのみ有効な変数を、バッファ・ローカルな変数と呼ぶ。

変数の通常の束縛、つまり、特定のバッファに関連していない束縛を デフォルトの束縛(default binding)と呼びます。多くの場合、これはグローバル束縛です。

バッファローカルな束縛のもっとも一般的な使い方は、メジャーモードでコマンドのふるまいを制御する変数に変更することです。たとえば、CモードやLispモードでは、変数paragraph-startを設定して、空行だけが段落を区切るように指定します。これには、CモードやLispモードになったバッファでは、変数をバッファローカルにしてから、そのモード用の新たな値を変数に設定するのです。

バッファローカルな束縛を作る普通の方法は、 make-local-variableです。メジャーモードのコマンドは典型的にこれを使います。これはカレントバッファだけに影響します。

バッファローカル変数の作成方法

これを使用すれば、グローバル変数をバッファローカルな変数に変更することもできる。

  • make-local-variable バッファローカル変数を作成する グローバル変数をバッファ固有の変数に変更することができる
              ;; バッファ`b1'では、
              (setq foo 5)                ; すべてのバッファに影響する
                   => 5
              (make-local-variable 'foo)  ; `b1'にローカル
                   => foo
              foo                         ; これは値を
                   => 5                   ;   変えない
              (setq foo 6)                ; `b1'での値を
                   => 6                   ;   変更する
              foo
                   => 6
    
              ;; バッファ`b2'では、値は変わっていない
              (save-excursion
                (set-buffer "b2")
                foo)
                   => 5
    
  • kill-local-variable バッファローカル変数を削除する
  • make-variable-buffer-local これから作成するものも含めたバッファすべてで、変数をバッファローカルにする。 その変数をバッファ固有の変数になるようにマークするだけである。このコマンドによってマークされた変数は、読み出し参照の場合は何もしない(グローバルのまま)が、値を変更しようとした途端にバッファローカル変数となる。 新たな値はバッファローカルな束縛に格納され、デフォルトの束縛(グローバル束縛)は変更しません。つまり、どのバッファでもデフォルト値をsetqでは変更できません。デフォルト値を変更する唯一の方法は、setq-defaultを使うことです。

save-excursion

複数のバッファにおいて変数にバッファローカルな値があるときに、変数をletで束縛してから、別の束縛が有効である別のバッファに切り替えてletを抜けると、 Emacsをとても混乱させることになる。こうすると、バッファローカルな束縛とデフォルトの束縛を混ぜ合わせてしまう。

混乱を避けるために、このような変数の使い方は避けてください。別のバッファに切り替える各コード部分をsave-excursionで囲めば、このような問題はありません。

;; だめな例
(setq foo 'b)
(set-buffer "a")
(make-local-variable 'foo)
(setq foo 'a)(let *1
  (set-buffer "b")
  body...)
foo => 'a      ; バッファ`a'の古いバッファローカルな値が
               ;   現在のデフォルト値
(set-buffer "a")
foo => 'temp   ; 消えているべきローカルなletの値が
               ;   バッファ`a'の現在のバッファローカルな値

;; 良い例 その他はだめな例と同じ(let *2
  (save-excursion
    (set-buffer "b") ;別のバッファに移動するコード部分を save-excursion で囲う
    body...))
;; body内でのfooへの参照は、バッファ`b'のバッファローカルな束縛を使います。

ローカル束縛

スペシャルフォームletやlet*は、ローカル束縛を作るためにあります。

letフォーム

let (bindings...) forms...

このスペシャルフォームは、bindingsに従って変数を束縛し、 formsのすべてをテキスト上の順に評価する。 letフォームは、formsの最後のフォームの値を返す。

let*フォーム

bindings内の式では、このlet*フォーム内でまえにあるシンボルを参照できる

(setq Y 2)
     => 2
(let* ((Y 1)
       (Z Y))    ; 設定し終えたばかりのYの値を使う
  (list Y Z))
     => (1 1)

結局 let と make-local-variable は何が違うのか

let は let フォーム内にローカルな変数を作成する

make-local-variable は バッファにローカルな変数を作成する

*1:foo 'temp

*2:foo 'temp

投稿したコメントは管理者が承認するまで公開されません。

スパム対策のためのダミーです。もし見えても何も入力しないでください
ゲスト


画像認証