Next: Error Symbols, Previous: Processing of Errors, Up: Errors [Contents][Index]
エラーをシグナルすることによる通常の効果は、実行されていたコマンドを終了してEmacsエディターのコマンドループに即座にリターンすることです。スペシャルフォームcondition-case
を使用してエラーハンドラーを設定することにより、プログラム内の一部で発生するエラーのをトラップを調整することができます。以下は単純な例です:
(condition-case nil (delete-file filename) (error nil))
これはfilenameという名前のファイルを削除して、任意のエラーをcatch、エラーが発生した場合はnil
をリターンします(このような単純なケースではマクロignore-errors
を使用することもできる。以下を参照のこと)。
condition-case
構文は、insert-file-contents
呼び出しによるファイルオープンの失敗のような、予想できるエラーをトラップするために多用されます。condition-case
構文はユーザーから読み取った式を評価するプログラムのような、完全には予測できないエラーのトラップにも使用されます。
condition-case
の2番目の引数は保護されたフォーム(protected
form)と呼ばれます(上記の例では保護されたフォームはdelete-file
の呼び出し)。このフォームの実行が開始されるとエラーハンドラーが効果をもち、このフォームがリターンすると不活性になります。その間のすべてにおいてエラーハンドラーは効果をもちます。特にこのフォームで呼び出された関数とそのサブルーチン等を実行する間、エラーハンドラーは効果をもちます。厳密にいうと保護されたフォーム自身ではなく、保護されたフォームから呼び出されたLispプリミティブ関数(signal
とerror
を含む)だけがシグナルされるというのは、よいことと言えます。
保護されたフォームの後の引数はハンドラーです。各ハンドラーはそれぞれ、どのエラーを処理するかを指定する1つ以上のコンディション名(シンボル)をリストします。エラーがシグナルされたとき、エラーシンボルはコンディション名のリストも定義します。エラーが共通のコンディション名をもつ場合、そのハンドラーがそのエラーに適用されます。上記の例では1つのハンドラーがあり、それはすべてのエラーをカバーするコンディション名error
を指定しています。
適切なハンドラーの検索は、もっとも最近に設定されたハンドラーから始まり、設定されたすべてのハンドラーをチェックします。したがってネストされたcondition-case
フォームに同じエラー処理がある場合には、内側のハンドラーがそれを処理します。
何らかのcondition-case
によりエラーが処理されると、debug-on-error
でエラーによりデバッガーが呼び出されるようにしていても、通常はデバッガーの実行が抑制されます。
condition-case
で補足されるようなエラーをデバッグできるようにしたいなら、変数debug-on-signal
に非nil
値をセットします。以下のようにコンディション内にdebug
を記述することにより、最初にデバッガーを実行するような特定のハンドラーを指定することもできます:
(condition-case nil (delete-file filename) ((debug error) nil))
ここでのdebug
の効果は、デバッガー呼び出しを抑制するcondition-case
を防ぐことだけです。debug-on-error
とその他のフィルタリングメカニズムがデバッガーを呼び出すように指定されているときだけ、エラーによりデバッガーが呼び出されます。Error Debuggingを参照してください。
マクロcondition-case-unless-debug
は、そのようなフォームのデバッギングを処理する、別の方法を提供する。このマクロは変数debug-on-error
がnil
、つまり任意のエラーを処理しないようなケース以外は、condition-case
とまったく同様に振る舞う。
特定のハンドラーがそのエラーを処理するとEmacsが判断すると、Emacsは制御をそのハンドラーにreturnします。これを行うために、Emacsはそのとき脱出しつつあるバインディング構成により作成されたすべての変数のバインドを解き、そのとき脱出しつつあるすべてのunwind-protect
フォームを実行します。制御がそのハンドラーに達すると、そのハンドラーのbodyが通常どおり実行されます。
そのハンドラーのbodyを実行した後、condition-case
フォームから実行がreturnされます。保護されたフォームは、そのハンドラーの実行の前に完全にexitしているので、そのハンドラーはそのエラーの位置から実行を再開することはできず、その保護されたフォーム内で作られた変数のバインディングを調べることもできません。ハンドラーが行なえることは、クリーンアップと、処理を進行させることだけです。
エラーのシグナルとハンドルにはthrow
とcatch
(Catch and Throwを参照)に類似する点がいくつかありますが、これらは完全に別の機能です。エラーはcatch
でキャッチできず、throw
をエラーハンドラーで処理することはできません(しかし対応するcatch
が存在しないときにthrow
を使用することによりシグナルされるエラーは処理できる)。
このスペシャルフォームはprotected-formの実行を囲い込むエラーハンドラーhandlersを確立する。エラーなしでprotected-formが実行されると、リターンされる値はcondition-case
フォームの値になる。この場合、condition-case
は効果をもたない。protected-formの間にエラーが発生すると、condition-case
フォームは違いを生じる。
handlersはそれぞれ、(conditions
body…)
というフォームのリストである。ここでconditionsはハンドルされるエラーコンディション名、またはそのハンドラーの前にデバッガーを実行するためのコンディション名(debug
を含む)。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 Symbolsを参照)。Emacsは1つ以上のコンディション名を指定するハンドラーにたいして、すべてのアクティブなcondition-case
フォームを検索する。condition-case
の最内のマッチがそのエラーを処理する。condition-case
内では、最初に適合したハンドラーがそのエラーを処理する。
ハンドラーのbodyを実行した後、condition-case
は通常どおりリターンして、ハンドラーのbodyの最後の値をハンドラー全体の値として使用する。
引数varは変数である。protected-formを実行するとき、condition-case
はこの変数をバインドせず、エラーを処理するときだけバインドする。その場合には、varをエラー記述(error
description)にバインドする。これはエラーの詳細を与えるリストである。このエラー記述は(error-symbol
.
data)
というフォームをもつ。ハンドラーは何を行なうか決定するために、このリストを参照することができる。たとえばファイルオープンの失敗にたいするエラーなら、ファイル名がdata(エラー記述の3番目の要素)の2番目の要素になる。
varがnil
なら、それはバインドされた変数がないことを意味する。この場合、エラーシンボルおよび関連するデータは、そのハンドラーでは利用できない。
より外側のレベルのハンドラーにcatchさせるために、condition-case
によりcatchされたシグナルを再度throwする必要がある場合もある。以下はこれを行なう方法である:
(signal (car err) (cdr err))
ここでerr
はエラー記述変数(error description
variable)で、condition-case
の1番目の引数は、再throwしたいエラーコンディション。Definition of signalを参照のこと。
この関数は与えられたエラー記述子(error descriptor)にたいするエラーメッセージ文字列をリターンする。これはそのエラーにたいする通常のエラーメッセージをプリントすることにより、エラーを処理したい場合に有用。Definition of signalを参照のこと。
以下は0除算の結果によるエラーを処理するために、condition-case
を使用する例です。このハンドラーは、(beepなしで)エラーメッセージを表示して、非常に大きい数をリターンします。
(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
を指定するので、division-by-zero(0除算)エラーだけを処理します。他の種類のエラーは(このcondition-case
によっては)、処理されません。したがって:
(safe-divide nil 3) error→ Wrong type argument: number-or-marker-p, nil
以下はerror
によるエラーを含む、すべての種類のエラーをcatchする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
この構文は、それの実行中に発生する任意のエラーを無視してbodyを実行する。その実行中にエラーがなければ、ignore-errors
はbody内の最後のフォームの値を、それ以外はnil
をリターンする。
以下はこのセクションの最初の例をignore-errors
を使用して記述する例である:
(ignore-errors (delete-file filename))
このマクロはいわばignore-errors
の穏やかなバージョンである。これはエラーを完全に抑止するのではなく、エラーをメッセージに変換する。これはメッセージのフォーマットに、文字列formatを使用する。formatは"Error:
%S"
のように、単一の‘%’シーケンスを含むこと。エラーをシグナルするとは予測されないが、もし発生した場合は堅牢であるべきようなコードの周囲にwith-demoted-errors
を使用する。このマクロはcondition-case
ではなく、condition-case-unless-debug
を使用することに注意。
Next: Error Symbols, Previous: Processing of Errors, Up: Errors [Contents][Index]