今回は The Basics
における Error Handling
の最後のところを見ていきます。とはいえスライド自体は前回で最後まで辿り着いているので、今回はその補足というのか、話しきれなかったエラーからの復帰まわりのもうひとつの書き方を紹介したいのと、これまでの話の中で出てきた Result
や LocalizedError
のような、エラー処理にまつわる各種型についても眺めてみるのも楽しそうな気がしたので、少しだけそれらにも着目してみることにしますね。
——————————————————————————————— 熊谷さんのやさしい Swift 勉強会 #184
00:00 開始 00:57 エラーからの復帰 01:29 break と continue が不自然な印象 02:31 ラベル付き do 03:40 continue でラベルに戻る 07:06 ラベル指定の continue を使ってみたい? 08:53 ラベル付き continue の意味するところは? 09:51 ブロックにラベルを貼るのは珍しい? 10:55 危険性はそんなになさそうな気はするものの⋯ 12:09 無限ループしたときの発見が遅れる懸念 13:08 慣れれば良い感じかもしれない? 14:17 読み手の驚きを低減することは重要 15:12 ラベル付き continue に関するテストコード 16:29 repeat - while と似ている? 17:25 ラベルはブロックと合わせて使う 21:26 switch 文で continue は使える? 23:11 fallthrough は特には何もない様子 24:04 これまでの内容整理と所感 26:39 クロージングと次回の展望 ———————————————————————————————
Transcription & Summarize : 熊谷さんのやさしい Swift 勉強会 #184
はい、じゃあ始めていきますね。今日はエラーハンドリングのお話の最後です。最後といっても、これは前回スクリプトしたスライドで、こっちも前回お話ししたスライドです。要はさっきのこのソースコードの解説をしているっていうところですね、これで終わりなので基本的に話は終わったんですよ。
ただもうちょっとだけエラーハンドリング周りで気になるところ、見ておきたいなと思うところが少し残っているので、それをゆっくりと見ていく回にしようかなと思います。前回のXcodeですが、そうですね、いろいろ見ていってましたね。
まずはエラーハンドリングの復習から先に見ていきましょうか。関数を使って最適にやっていくっていうお話をしてもらったりとか、これについてはいい感じで、基本的にはこういうスタイルになっていくんだなって話してて思ったんです。でももう一つ、前に紹介した自分が最初に書いたコードですね、while true
を使って回していって、break
を使うという書き方、これなんか違和感があったんですよね。書いてて思ったんですが、それで自然な書き方としてさっき紹介してもらって書いた感じですけど、この辺りについてもう少しだけ見てみたいと思います。
なんでこれが違和感を持つような、break
を書かなきゃいけないとなったんだって思ったんです。フラグを使ったからかな?これが最初に思い浮かんだけど、実は普通やんないよねっていう例だったのかな?普通に開かないですよね、break
なんでね。この中で何故か不思議な感じがするんですよ。それはそれとして置いといて、これがちょっと面白い書き方だとみんな知ってるのかな?と思ったんですが、自分は全然知らなかったので、みんな知ってるのかなっていう一般的なのかなっていう意味です。これ、while
ループ怖いじゃないですか。
前回ね、前回まあ忘れたけど、break
を書き忘れたことによって無限ループに陥ったみたいな、そんな事例もありましたよね。while
ループ恐さにハマったわけですけど、これ、while
ループを使わなくても書けるの知ってましたか?この勉強会を通して知った知識で思いついたんですけど、do
があるじゃないですか。だからこのdo
を活用するんですよ。while
ループを取ったコードはこうです。
do {
// ここの処理
} while condition
そうなんですよ。これできます。このラベルも初めて知ったんですけど、まず当然、break
がいらないんですよ。これでcontinue
が使えるのもびっくりしました。これが使える色も出ますね。ちなみにここであるのはbreak
を消しているのが確認できます。これを消してみても同じくコンティニューが使えるので、ラベルを使った場合の通常のcontinue
では戻れなくても、ラベル付きのループは戻れます。これが一般的かどうかはわからないですけど、多くの人が気持ち悪いと思うと思うんですが、すごくないですか?
試しにここにprint
を入れる必要もないですが、もしi
と書いてあればi
って出ますね。例えば以下のようなコードです。
var i = 0
repeat {
i += 1
if i == 10 { break }
print(i)
} while true
この場合、1
から9
まで出力されて、その後i
が10
になった時点でループが抜けます。こうした書き方もできるので、ぜひ試してみてください。 さて、リカバリーするわけですね。では、一旦試してみましょう。メーカーさんとイッチ関数内でやる必要はないかと思いますが、あの辺でスローをかけるのはちょっと分かりにくいので、やはりこういう感じでスローしました。サンドウィッチエラーやアウトオブクリンディシーズンが発生する場合、コース開かずともベルブを洗わないといけないから、実際どうすればいいのか無理やりやってみますか。
本来はランダムを使っちゃダメですが、イフゴールランダムを使って関数が増えちゃいましたね。そうですね、何回かに一度失敗するかが無くなるのを動かして、私の方でね。何か間違っているかな?何も用意してないからか。ここで2個買ってあげると、1回は上げられた。こんな感じで、ほら、3回失敗して1回成功して終わった。すごいですよね。
これを話したくてしょうがなかったんですけど、印象はどうですか?使ってみたいとか思った人いますか?はい、新しいコンティニューの使い方がループ以外でもできるってのは、発見な気がしましたね。ちょっと面白いですよね。ループ以外でこれしか発想が無かったですよね。自分でも無くて、たまたま見つけたんですよ。
昔よくやってたアルゴリズムだと、2階建てループをやる必要があって、その時よくアルゴリズムを使ってました。2階建てループの中でどのループを記入してどのループをプレイするかとかよくやってたんで、その時に見つかったんですけど、2回これを入れる発想がなかったんですね。それと同じ発想なんです、これ。
だから買い道がそうやってあるんでしょうね。doブロックの活用の幅が広がって、非常に面白い。リカバリーとしてうまく機能していますね。無限ループが起きる可能性はファイルループと同じですが、そこはしょうがないです。ただ、理屈上どうしても出てきてしまうので、ちょっと研究して一般化を目指してもらえると面白いかもしれません。
他にこれを見て使いどころが思い浮かぶ人いますか?doコンティニューを使ってdoに戻るということはどういうことか。まあ、go toみたいな感じがします。例えばファイルループとかがまさにそれですね。C言語スタイルのループみたいな感じにはなりますが、リピートファイルでコンティニューを使うのは自然な発想です。
しかし、doブロックにラベルを貼ってスコープを限定し、それにラベルを貼るというのは構造化プログラミングでは珍しいかもしれません。アセンブラではラベルを貼ってジャンプすることが一般的でしたが、プログラミング言語ではそれほど一般的ではないので、面白い使い方です。
コンティニューが他の場面で使える可能性について考えると、doブロックの中でどこからでも戻れる恐怖感は少なくともないですね。その中でリカバリーできないといけないので、無限ループを防ぐ意味でも有用です。無限ループするリスクはありますが、そのメリットが上回るのであれば別の方法で実装すればいいです。デバッガーを使って止めたりとか、手動で一時停止をすることもできますから、デバッガーと一緒に理論でカバーすれば悪くないと思います。
ただし、無限ループするリスクも考慮すべきです。デバッグやスタックオーバーフローのリスクがあるので、そのバランスを見て使用を考えるのが良いでしょう。無限ループなどの懸念を払拭できれば、非常に面白いアプローチだと思います。 今の自分が慣れていないだけの問題として、特にラベルが付いているブロックで無限ループする恐れがあるという点を見落としがちです。しかし、ラベルが付いていれば、その目的が明確になるので、それほど怖いことではないかもしれませんね。このコードについてですが、感覚としては、アンラップの使用が怖いから使わないでおこうという主流の考え方に似ています。当時と同じように、新しい可能性を感じると、使ってみたくなるかもしれませんが、それは状況次第です。
ホワイル文の代わりにあえてこの方法を使うのは問題がありますが、繰り返しのブロックだと主張するのであれば、ホワイルの方が明確で良いでしょう。一方、「ブー」は汎用的すぎて、何のためにラベルが付いているのかが分かりにくいことがあります。でも、これは慣れの問題かもしれませんね。「ブー」にラベルが付いていれば、何に使いたいのかが明確になる気がします。話が延々と続いてしまうので、この辺でやめておきます。何にしても、ブーブロックを使ったエラーリカバリーの手段があるということを覚えておいてください。
テストを書くのが推奨されており、実際にテストを書かれたものが12月のラベルについて検証されていました。興味深いのは、「ずーラベルどう」というテストで、コンティニューラベルも使われていました。こうした使い方は新しく、スイフトの新しい側面を感じさせますが、基本的には条件式でコンティニューラベルを使うのが自然ですし、あり得る使い方ですね。
この条件式が特定の場所に出てくるために特殊に見えますが、最後に条件式を書いている場合にdoを使うのはリピートファイルだと思います。リピートファイルは確かdoを使っていましたね。リピートファイルとdoの方が分かりやすいかもしれませんが、リピートしない場合はdoの方が適していますね。
もう一つ送ってもらったラベルについてのコードも確認しましたが、こちらも特定のパースエラーが発生し、戻れる場所が限定されるような状況でした。全体として、このようなラベルやコンティニューの使い方を理解し、有効に使うためには、少し慣れが必要です。また、コード構造をしっかりすることも重要です。 ループの中での break
や continue
についての話がありました。まず、if
文の中で break
を使っても、if
文自体はブロックを抜けませんが、外側の構造を抜けます。したがって、if
文は continue
や break
の対象にはなりません。
次に switch
文について話がありました。switch
文では break
を使うことができます。ただし、switch
文で continue
は使えないようです。ラベルを使った場合についても試してみましたが、うまくいかないようでした。
条件を評価するような文、例えば if
文、switch
文、guard
文などにおいて、continue
は使えないことがわかりました。一方、ループ (do
ブロック、while
、repeat-while
) では、ラベル付きの continue
が使えるようです。
また、switch
文では fallthrough
を使えるが、if
文では意味がないので使えないという話がありました。もし if
文で fallthrough
が使えたら面白いかもしれませんが、コードが複雑になる可能性があるので避けた方が良いでしょう。
話題の一つとして、データの正規化や特定の条件までデータを整えるような場合には、do
ブロックが有効な使い方であることが挙げられました。ラベルを使ってループを回すことで、コードの意味を明確にすることができます。大文字でラベルを書くことができますが、良い感じに名前を整えて、意味のあるラベルにすることもできます。
次回の勉強会ではエラーハンドリングについて再度検討する予定です。エラーハンドリングの方法について話し合う際に、以前紹介した do
ブロックと continue
を使った例を含めて、他にアイデアがあれば共有してほしいというリクエストがありました。
今回の勉強会はこれで終了となります。参加者の皆さん、ありがとうございました。