次: , 前: Defining Variables, 上: Variables


10.6 変数を堅牢に定義するためのヒント

(内部に束縛を含むようなキーマップなどの)複雑な値を保持する変数を 定義し初期化するときには、つぎのように、 値の計算全体をdefvarの内部に入れておくのが最良です。

     (defvar my-mode-map
       (let ((map (make-sparse-keymap)))
         (define-key map "\C-c\C-a" 'my-command)
         ...
         map)
       docstring)

この方法には、いくつかの利点があります。 まず、ファイルのロード中にユーザーが中断した場合、 変数は初期化されないか正しく初期化されるかのいずれかであり、 その中間状態ということはありません。 第2に、変数をすでに初期化したあとにファイルをロードし直しても、 変数を変更しません。 (キーをバインドし直すなどの)内容の一部を変更するために ユーザーがフックを実行した場合などには、これは重要です。 第3に、C-M-xでフォームdefvarを評価すると、 マップを完全に初期化し直せます

フォームdefvarの内側に多くのコードを置くことには、欠点が1つあります。 変数の名前を指定した行から説明文字列が離れすぎてしまうことです。 つぎのようにしてこれを安全に防げます。

     (defvar my-mode-map nil
       docstring)
     (if my-mode-map
         nil
       (let ((map (make-sparse-keymap)))
         (define-key my-mode-map "\C-c\C-a" 'my-command)
         ...
         (setq my-mode-map map)))

これには、defvarの内側に初期化を入れたときと同じ利点がありますが、 変数を再初期化するには、各フォームそれぞれについて C-M-xを打つ必要があります。

しかし、つぎのようなコードは書かないでください。

     (defvar my-mode-map nil
       docstring)
     (if my-mode-map
         nil
       (setq my-mode-map (make-sparse-keymap))
       (define-key my-mode-map "\C-c\C-a" 'my-command)
       ...)

このコードでは、変数を設定してから変更しますが、 それを複数の手順で行います。 setqの直後にユーザーが中断すると、 変数は正しく初期化されておらず、空でもnilでもありません。 こうなったときにファイルを再ロードしても変数を初期化できません。 変数は不完全な状態のままです。