スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

F#入門第35回(例外(Exception)(2))

今回のお題は「例外(Exception)(2)」です。
 
まずは宿題の解答から
(宿題)
(*01*)  let tryDepth2 () =
(*02*)     try
(*03*)          printfn "in Depth2 try first"
(*04*)          printfn "%d" (3/0)
(*05*)          printfn "in Depth2 try last"
(*06*)     with
(*07*)      | :? System.IndexOutOfRangeException ->printfn "配列境界外"   
(*08*)     printfn "now quit tryDepth2"
(*09*)      
(*10*)  let tryDepth1 () =
(*11*)      try 
(*12*)          printfn "in Depth1 try first"
(*13*)          tryDepth2 ()
(*14*)          printfn "in Depth1 try last"
(*15*)      with
(*16*)      | :? System.DivideByZeroException  ->printfn "0で割った"
(*17*)      printfn "now quit tryDepth1"
(*18*)  
(*19*)  let testTry () =
(*20*)      tryDepth1 () 
 
解説20から、10を呼び出し、11でtry部分に入ります。12で"in Depth1 try first"と表示し、13で01を呼び出し、02でtry部分に入り、03で"in Depth2 try first"と表示します。
04で例外がraiseされ06以下のパターンマッチが試みられますが、マッチするものがないので、呼び出し元の15以下のパターンマッチが試みられて、16でマッチするので「0で割った」と表示され、17が実行されて"now quit tryDepth1"と表示されて終了します。
実行例はつぎのようになります。
 
> testTry ();;
in Depth1 try first
in Depth2 try first
0で割った
now quit tryDepth1
val it : unit = ()
 
さて今日はまず、tyr (式1) finally (式2)の形を紹介します。
まず、(式2)はunit型でないといけないことに留意してください。
これは、tryブロックの部分で、例外が発生すると、まずfinally ブロックが実行され、それから例外がraiseされる、という処理がなされます。
次の例をみてください。
 
(*01*)  let tryDepth2 () =
(*02*)     try
(*03*)          printfn "in Depth2 try first"
(*04*)          printfn "%d" (3/0)
(*05*)          printfn "in Depth2 try last"
(*06*)     finally
(*07*)        printfn "now in tryDepth2 finally block"
(*08*)     printfn "now quit tryDepth2"
(*09*)      
(*10*)  let tryDepth1 () =
(*11*)      try 
(*12*)          printfn "in Depth1 try first"
(*13*)          tryDepth2 ()
(*14*)          printfn "in Depth1 try last"
(*15*)      with
(*16*)      | :? System.DivideByZeroException  ->printfn "0で割った"
(*17*)      printfn "now quit tryDepth1"
(*18*)  
(*19*)  let testTry () =
(*20*)      tryDepth1 () 
 
これは、宿題の6、7行目のwith部分をfinallyブロックに変えたものです。
宿題での実行例は
 
> testTry ();;
in Depth1 try first
in Depth2 try first
0で割った
now quit tryDepth1
 
でしたが、こちらの実行例は
 
> testTry ();;
in Depth1 try first
in Depth2 try first
now in tryDepth2 finally block
0で割った
now quit tryDepth1
 
となり、例外がraiseされる前にfinallyブロックが実行されていることが確認できると思います。
 
次は、マッチした例外を再び、投げかける関数rethrow ()です。
次の例を見てください。
 
let tryDepth2 () =                                      //1
   try                                                  //2
        printfn "in Depth2 try first"                   //3
        printfn "%d" (3/0)                              //4
        printfn "in Depth2 try last"                    //5
   with                                                 //6
    | :? System.DivideByZeroException                   //7
              ->printfn "0で割った matched in Depth2"  
                 rethrow ()  //ここ頭は上の行のprintfnと揃っている    //8
      
let tryDepth1 () = 
    try  
        printfn "in Depth1 try first" 
        tryDepth2 () 
        printfn "in Depth1 try last" 
    with 
    | :? System.DivideByZeroException   
        ->printfn "0で割った matched in Depth1" 
    printfn "now quit tryDepth1"
   
let testTry () = 
    tryDepth1 ()
 
これは宿題の7行目のSystem.IndexOutOfRangeExceptionをSystem.DivideByZeroExceptionに変更して、ここで例外がマッチするようにして、その上で8行目でこの例外をrethrowしたものです。
実行結果は次のようになります。
 
> testTry ();;
in Depth1 try first
in Depth2 try first
0で割った matched in Depth2
0で割った matched in Depth1
now quit tryDepth1
val it : unit = ()
 
さて最後に自分で例外を定義してそれをraiseする方法を紹介します。
これには次のような二つの方法があります。
 
(1).System.Exceptionクラスを継承したクラスを定義して、それをインスタンス化してraiseする。
(2)lightweight exception syntaxを利用する。
 
ここでは(2)の方法を紹介したいと思います。
 
自分で例外の型を定義するには次のようにします。
exception ident [ of type ] //[of type]の部分は省略可という意味です。
例えば、三つの自前の例外の型を定義してみます。
exception MyException1 
exception MyException2 of string
exception MyException3 of int list
次に引数によって、これらのどれかをraiseして、マッチさせる関数test を定義してみます。
let test arg =
    try
        match arg with
        | 0 -> raise MyException1
        | 1 -> raise (MyException2 ("messege for test"))
        | _ -> raise <| MyException3 [1;2;3]
    with
    |MyException1       -> printfn "chosen 0"
    |MyException2 s     -> printfn "chosen 1 and str = %s" s
    |MyException3 lst   -> printfn "chosen not 0 or 1 and list = %A" lst  
    
 
実行例
> test 0;;
chosen 0
val it : unit = ()
 
> test 1;;
chosen 1 and str = messege for test
val it : unit = ()
 
> test 2;;
chosen not 0 or 1 and list = [1; 2; 3]
val it : unit = ()
 
ということで、付加情報ありの、自前の例外が簡単につくれてしまうのでした。
では、宿題です。
付加情報ありの、自前の例外を何か作り、raiseして、マッチでつかまえてみるコードを何か書いてみてください。
(この宿題については、上のコードが一つの解答例ですので、特に別解答はしませんので、自分で試してください。)
 
スポンサーサイト

テーマ : プログラミング
ジャンル : コンピュータ

コメントの投稿

非公開コメント

typo

宿題の回答
(*08*) printfn "now quit tryDepth2"
の部分、インデントが空白1つ深い。
with の"w"にあわせる

rethrow の例
つづりが rethow で、r が抜けている。
インデントがあっていない。

No title

細かい部分まで見て頂いてほんとありがとうございます。助かります。
プロフィール

T GYOUTEN

Author:T GYOUTEN
F#と英単語とフリーソフトと読書に興味があります。
ホームページでフリーソフトも公開しています。どぞ御贔屓に。

最新記事
最新コメント
最新トラックバック
月別アーカイブ
カテゴリ
フリーエリア
フリーエリア
blogram投票ボタン
検索フォーム
RSSリンクの表示
リンク
ブロとも申請フォーム

この人とブロともになる

QRコード
QRコード
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。