[scala]for + try catch + breakなやりかた


scala初心者が始めてscalaにアタックした際の備忘録。

やりたいこと

1. for文で数回処理を走らせてたい
2. for文の中でtry catchし、一回でもうまく行ったらforを抜け出したい

scalaにはbreakもcontinueもない

関数型なので、手続き型と同じ気分では使えない。
でもforを抜け出したい。さらにtry catchもしたい場合、どうするべきなのか?
答えから言えばbreakableを使うことになるものの、挙動がちょっと難しかったので確認。

いくつか考えた手段

1. breakableの中でtryで使う

http://stackoverflow.com/questions/2742719/how-do-i-break-out-of-a-loop-in-scala?answertab=active#tab-top
http://qiita.com/tanigon/items/96f45b3dcdd15b04cc89

イメージとしては

breakable{
  for {
    try{
     ...
     break
    }
    catch{
      case a: Throwable =>
        println("case a")
    }
  }
}

しかしこれではダメ。
実装を見ると、例外を投げることで処理を抜けだしている。
つまりbreakは疑似例外であるらしい。
したがってtry catchのtry側で抜けだそうとすると、後段でcatchされて例外処理が走ってしまいます。
よって結局forの規定回数だけtryされてしまうことになります。

2. for の中で例外吐いてcatchでforのcountをマックスまで増やす

for文の中で例外を吐かせて、例外をキャッチした場所で

catch{
  case break: Throwable =>
    i = max_iteration
}

とかやって、loop用変数を強制的に増やしてやれば回数を飛ばせると思ったんですが、scalaのforではそいつはvarではなくてvalらしいので、再代入ができません。

3.breakableをcatchで使う

最終的に落ち着いた案。
例外をtryに埋め込み、catchして場所でさらにbreak(擬似例外)を投げると抜けられます。
つまり

breakable{
  for {
    try{
      ...
      throw GOTOBREAK
    }
    catch{
      case GOTOBREAK =>
        break
      case a: Throwable =>
        ...
    }
  }
}

ってやって、catchの中でbreakしてやればokです。

とはいえ

これって関数型言語の書き方じゃないんだろうなぁというところではあります。
難しい。

シェアする

  • このエントリーをはてなブックマークに追加

フォローする