Next: Error Symbols, Previous: Processing of Errors, Up: Errors
エラーを通知することの普通の効果は、
実行中のコマンドを終了し、Emacsのエディタコマンドループにただちに戻ります。
読者のプログラムの一部で発生したエラーを捕捉するようにするには、
スペシャルフォームcondition-case
を使ってエラーハンドラを設定します。
単純な例はつぎのようになります。
(condition-case nil (delete-file filename) (error nil))
これはfilenameという名前のファイルを削除しますが、
エラーが発生するとどんなエラーでも捕捉してnil
を返します。
condition-case
の第2引数を
保護されたフォーム(protected form)と呼びます。
(上の例では、保護されたフォームはdelete-file
の呼び出し。)
このフォームの実行を開始するとエラーハンドラが有効になり、
このフォームから戻るとエラーハンドラは取り除かれます。
そのあいだは、つねにエラーハンドラは有効です。
特に、このフォームから呼び出される関数の実行中、
それらのサブルーティンの実行中などには、エラーハンドラは有効です。
これは大切なことで、厳密にいえば、
エラーが通知されるのは、保護されたフォームから呼び出された
(signal
やerror
を含む)Lisp基本関数の実行中であって、
保護されたフォームそのものからではないからです。
保護されたフォームのうしろにある引数は、ハンドラです。
各ハンドラは1つ以上の(シンボルである)条件名
(condition names)を列挙し、処理するエラーを指定します。
エラーが通知されたときのエラーシンボルも条件名のリストを定義します。
それらに共通の条件名があるとき、
エラーハンドラがエラーに適用されます。
上の例では、1つのハンドラがあり、条件名は1つ、error
を指定しています。
この条件名はすべてのエラーを意味します。
適用可能なハンドラの探索では、
もっとも最近に確立されたハンドラから始めて、
確立されたすべてのハンドラを調べます。
したがって、フォームcondition-case
が2つ入れ子になっていて
同じ名前のハンドラを確立していると、内側のものが実際に処理を受け持ちます。
フォームcondition-case
でエラーが処理されるときには、
debug-on-error
でエラーによりデバッガを起動するように指定してあっても
デバッガは実行されません。
See Error Debugging。
condition-case
で捕捉されるエラーをデバッグしたいときには、
変数debug-on-signal
にnil
以外の値を設定します。
エラーを処理できる場合には、制御はハンドラに移ります。
こうするまえに、Emacsは、抜け出し対象となる束縛作成構造が設定した
すべての変数束縛を解き、抜け出し対象となるフォームunwind-protect
すべての後始末を実行します。
ハンドラに制御が移ると、ハンドラの本体を実行します。
ハンドラ本体の実行を完了すると、
フォームcondition-case
から戻ります。
ハンドラを実行するまえに保護されたフォームから完全に抜けているので、
ハンドラでは、エラー発生時点から再開したり、
保護されたフォームの内側で作られた変数束縛を調べたりすることはできません。
ハンドラでできることは、後始末をして先へ進むことだけです。
condition-case
構造は、insert-file-contents
の呼び出しで
ファイルのオープンに失敗するなどの予測可能なエラーを捕捉するために
しばしば使われます。
プログラムがユーザーから読み取った式を評価する場合のように、
まったく予測不可能なエラーを捕捉するためにも使われます。
エラー通知とエラー処理は、throw
とcatch
に多少似ていますが、
それらはまったく別の機能です。
catch
ではエラーを捕捉できませんし、
エラーハンドラではthrow
を処理できません
(しかしながら、適切なcatch
がないthrow
を使うと、
処理できるエラーを通知する)。
このスペシャルフォームは、protected-formの実行中は エラーハンドラhandlersを確立する。 protected-formがエラーなしに完了すると、 その戻り値がフォーム
condition-case
の値になる。 この場合、condition-case
はなんの効果もない。 フォームcondition-case
で違いがでるのは、 protected-formの実行中にエラーが起こった場合である。各handlersは、
(
conditions body...)
の形式の リストである。 ここでconditionsは、処理すべきエラーの条件名か条件名のリストである。 bodyは1つ以上のLisp式であり、 このハンドラがエラーを処理するときに実行される。 ハンドラの例を示す。(error nil) (arith-error (message "Division by zero")) ((arith-error file-error) (message "Either division by zero or failure to open a file"))生起する各エラーには、 そのエラーの種類を表すエラーシンボル(error symbol)がある。 そのシンボルの属性
error-conditions
は、 条件名のリストである(see Error Symbols)。 Emacsは、有効なフォームcondition-case
すべてを探索し、 これらの条件名を1つ以上指定したハンドラを探す。 もっとも内側の一致するcondition-case
がエラーを処理する。 このcondition-case
の内側では、 適用可能な最初のハンドラがエラーを処理する。ハンドラの本体の実行を完了すると、
condition-case
は通常のように戻り、 ハンドラの本体の最後のフォームの値を全体としての値に使う。引数varは変数である。
condition-case
は、protected-formを実行するときには この変数を束縛せず、エラーを処理するときだけ束縛する。 そのとき、varはローカルにエラー記述 (error description)に束縛される。 これは、エラーの詳細を与えるリストである。 エラー記述は、(
error-symbol.
data)
の形式である。 ハンドラは、動作を決定するためにこのリストを参照できる。 たとえば、ファイルのオープンに失敗したエラーであれば、 dataの第2要素、エラー記述の第3要素がファイル名である。varが
nil
であると、変数を束縛しなことを意味する。 そうすると、ハンドラではエラーシンボルと関連するデータを使えない。
この関数は、指定したエラー記述に対するエラーメッセージ文字列を返す。 エラーに対する普通のエラーメッセージを表示して、 エラーを処理したい場合に便利である。
ゼロ除算の結果であるエラーを処理するcondition-case
の使用例を示します。
ハンドラはエラーメッセージを(ベルを鳴らさずに)表示して、
大きな数を返します。
(defun safe-divide (dividend divisor) (condition-case err ;; 保護されたフォーム (/ dividend divisor) ;; ハンドラ (arith-error ; 条件 ;; このエラーに対する普通のメッセージを表示する (message "%s" (error-message-string err)) 1000000))) safe-divide (safe-divide 5 0) -| Arithmetic error: (arith-error) 1000000
ハンドラは条件名arith-error
を指定しているので、
ゼロ除算エラーだけを処理します。
少なくともこのcondition-case
では他の種類のエラーは処理しません。
したがって、つぎのようになります
(safe-divide nil 3) error--> Wrong type argument: number-or-marker-p, nil
以下は、error
で通知されるエラーも含めて、
すべての種類のエラーを捕捉するcondition-case
です。
(setq baz 34)
34
(condition-case err
(if (eq baz 35)
t
;; これは関数error
の呼び出し
(error "Rats! The variable %s was %s, not 35" 'baz baz))
;; これはハンドラ。フォームではない
(error (princ (format "The error was: %s" err))
2))
-| The error was: (error "Rats! The variable baz was 34, not 35")
2