Next: Error Symbols, Previous: Processing of Errors, Up: Errors [Contents][Index]
エラーをシグナルすることによる通常の効果は、実行されていたコマンドを終了して、Emacsエディターのコマンドループに即座にreturnすることです。スペシャルフォーム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
の呼び出しです)。このフォームの実行が開始されると、エラーハンドラーは効果をもち、このフォームがreturnすると不活性になります。その間のすべてにおいて、エラーハンドラーは効果をもちます。特に、このフォームで呼び出された関数、およびそのサブルーチンなどを実行する間、エラーハンドラーは効果をもちます。厳密にいうと、保護されたフォーム自身ではなく、保護されたフォームにより呼び出されたLisp基本関数(signal
とerror
を含む)だけがシグナルされるというのは、よいことです。
保護されたフォームの後の引数はハンドラーです。各ハンドラーは、どのエラーを処理するかを指定する、1つ以上のコンディション名(condition
names)(シンボル)をリストします。エラーがシグナルされたとき、エラーシンボルはコンディション名のリストも定義します。エラーが共通の条件名をもつ場合、そのハンドラーはそのエラーに適用されます。上記の例では、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が実行された場合、returnされる値は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
は通常どおりreturnし、ハンドラーの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)にたいするエラーメッセージ文字列をreturnします。これは、そのエラーにたいする通常のエラーメッセージをプリントすることにより、エラーを処理したい場合に有用です。Definition of signalを参照してください。
以下は、0除算の結果によるエラーを処理するために、condition-case
を使用する例です。このハンドラーは、(beepなしで)エラーメッセージを表示して、非常に大きい数をreturnします。
(defun safe-divide (dividend divisor)
(condition-case err
;; 保護されたフォーム。
(/ dividend divisor)
;; ハンドラー。 (arith-error ; Condition. ;; このエラーにたいする、通常のメッセージを表示する。 (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内の最後のフォームの値をreturnし、それ以外はnil
をreturnします。
以下は、このセクションの最初の例を、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]