このところは The Basic
の オプショナルバインディング
を眺めていっています。これについてもおおよそ見終えた感じですけれど、新しく登場した if let 省略表記
など、オプショナルバインディングを少し発展させたところについては、これまで余談として話す程度でそれそのものにじっくり着目してこなかったので、それについて着目してみます。
今回はお久しぶりにゆめみ社外の人を招いての開催になります。一般の人も若干名参加してくださる見込みですので、どうぞよろしくお願いしますね。
————————————————————————————————————— 熊谷さんのやさしい Swift 勉強会 #162
00:00 開始 00:11 前回のあらすじ 01:28 オプショナルバインディングの特色 02:09 細かく見ていく感覚にも意識を向けながら 03:37 シャドーイング 04:58 if let 省略表記 06:55 if let 省略表記は分かりやすい? 08:51 if let 省略表記で self は使える? 11:10 self のバックティック表現 12:47 オプショナルバインディングとは別ものと捉えて良さそう 13:19 var を使った if let 省略表記 14:24 if var 省略表記とは言わない? 14:57 if let 省略表記の使える場所 15:30 switch はパターンマッチング 16:13 while でオプショナルバインディングは使えた? 20:36 guard によって展開された weak self の暗黙利用 22:32 キャプチャーリストで self を明記 25:34 構造体はキャプチャー時に self を省略可能 26:42 キャプチャーとクロージングオーバー 30:30 inout は Copy-in Copy-out 31:00 値型の参照渡しは制御が難しそう —————————————————————————————————————
Transcription & Summarize : 熊谷さんのやさしい Swift 勉強会 #162
さて、では始めていきますね。もう10日前の話なので、ちょっと忘れてしまっている方も多いかなと思いますし、自分自身も結構忘れていたんですけど、オプショナルバインディングの特色について色々と話しているところです。
前回は主にGenericsの優先順位や存在型(エグジステンシャルタイプ)について話しましたね。前回ひたすら「エグジステンシャルタイプ」って呼んでいましたが、興味のある方は前回のアーカイブを見ていただけると良いかと思います。動画アーカイブは今後徐々に公開されていくので、「エグジステンシャルタイプ」についてもっと知りたいという方は、前回の回が公開された時にチェックしてみてください。今回はその話を知らなくても大丈夫です。
オプショナルバインディングの話に戻りますね。オプショナル型変数が何らかの値を持っていたらそれを取り出して使い、持っていなければ他の処理を行うという構図のことをオプショナルバインディングと呼びます。例えば、次のようなスニペットがあります。
if let value = optionalValue {
// value を使用
} else {
// 値がない場合の処理
}
この場合、変数 optionalValue
が値を持っていれば、その値が value
にバインドされ、次のブロックが実行されます。値がなければ else
ブロックが実行されます。
オプショナルバインディングは、Swift入門書などでも取り上げられており、それほど難しい内容ではありません。しかし、この勉強会では5~6回にわたって一時間ずつ深掘りしています。こんなに話が広がるのもプログラミングの面白いところですね。このように一つのトピックから様々なアイデアが生まれることが、より良いコードを書くきっかけになると思います。
さらに、オプショナルバインディングを使う際に便利な「シャドウイング」についても話しました。シャドウイングによって、元のオプショナル型変数を非オプショナルな変数で上書きすることで、わざわざアンラップしなくても済むようになります。
新しいバージョンでは、このオプショナルバインディングの書き方がさらに便利になりました。例えば、以下のスライドで説明したように、右辺がオプショナルを返す部分に対して、より短い表記が可能となりました。
if let number = optionalNumber {
// optionalNumber が非オプショナルで number として使える
}
このように、頻繁に使われるコードをシンプルにするための新機能が追加されています。イフレットのオプショナルバインディングのコードを短い文字で表記できるようにするというものです。この改善により、より効率的なコーディングが可能になります。
さて、本日の勉強会も有意義なものにしていきましょう。これからさらに深掘りしていく予定ですので、ぜひ楽しんでください。 この構文で新たに定義する変数名だけを書いてあげる。そうすると、イコールなんとかがない場合には同じ名前の変数をシャドウイングして使うという意味になります。これによってすんなりと処理が進むようになるでしょう。
実際にコードを見てみると、例えば7行目が動いていましたが、もし5行目だったら値を適切に設定することで4行目もちゃんと動作します。そしてこの単純なvalue
変数はオプショナルではなく、ちゃんとシャドウイングされたint
型になっているというわけです。これが新しい機能の特徴になります。多分今後、この機能をどんどん使っていくことになるでしょう。
用法が明確であれば、あえて書いてあげるという選択肢もあるでしょうけど、これは身についてしまえば直感的に使えると思います。最初は少し馴染まない人もいるかと思いますが、すぐに馴染むでしょう。これを積極的に使わない理由は多分ないと思います。
逆に懸念している人はいるでしょうか。これは今の感覚ではわかりにくくなることもありますが、もっと大きな問題があるかもしれません。読みづらさによって間違いを引き起こす可能性があると考えた場合、何か問題が起こりそうでしょうか。
自分自身は今のところ大きな問題は感じません。基本的に大丈夫だと思います。if let
でバリューが抜けているだけですからね。if let
でわかるので、ちょっと驚くかもしれませんが、これは特に問題ではないでしょう。
少し実際にやってみましょうか。weak self
も適用できますよね。if let
で問題はありません。以前はバックティックで括らなければいけなかった記述が、今は括らなくても良くなったとかでしたっけ。それは確かに今はできないですが、コンパイラのバグで括れています。
このように、オプショナルバインディングが簡単にできるようになりました。表示をするとよくわかりますが、if let
でオプショナルを解けますね。この新しい構文に慣れるまで少し時間がかかるかもしれませんが、特に難しい問題はないでしょう。
また、この新しい構文ではセルフもweak self
もちゃんと動作します。他の形としても認識されますが、これもバックティックで認識されるため、特に問題はないでしょう。
まとめると、新しいオプショナルバインディングの構文に少し時間がかかるかもしれませんが、一度慣れてしまえば非常に直感的に使えるようになります。これで以前の問題も解決できますし、今後も積極的に使っていくことになるでしょう。 なので、こういう頭の切り替えが必要です。「これがあるとかないとか」という話ではなく、状況に応じてオプショナルバインディングやリフレットショートハンドを使い分けるという感じですね。こんな感じで少しずつ馴染んでいけばいいと思います。やっていることはそれほど変わりません。この次のスライドで少し説明しますが、イフバーブロックの使い方について、以前も話したことがあります。この時、値を仮に value = 2
と書いて2倍にしたとします。このとき、タトゥーイング(タッピング)のされる方が終わっているので、プリントされるときに10と出ても、その後では元に戻っているという注意が必要です。これは普通のタトゥーイング(タッピング)の注意事項と同じです。
リフレットショートハンドが何をしているかイメージできれば、問題はありません。複雑になることは少ないです。リフレットで大部分が対応できるので、それほど難しくないでしょう。ただ、リフレットショートハンドなのに「イフバー」という名前が少し変ですね。オプショナルバインディングなら、レッドでもバーでも公平性はないですが、「イフバーショートハンド」とは言わないでしょう。これは少し変な感じです。
次に、他のガードとかの話をしましょう。リフレットショートハンドは、オプショナルバインディングが使えるところで使えます。例えば、guard let value else { fatalError() }
という感じでコードを書いても動きます。また、スイッチはパターンマッチングになるので少し別の感じですが、switch value { case let value }
と書くと、完全にバリューバインディングパターンが使われるので、どんな値でもマッチします。ニルの場合でもマッチするので、オプショナルパターンを使うことになるわけです。どちらにしても、書き方が似ています。
次に、条件文で使える例として、while let value
これだと無限ループする可能性があるので注意が必要です。また、トッププロパティにするときは以下のコードです。
if let value = someOptionalValue {
print(value)
}
ただし、これはオプショナルバインディングではなく、オプショナルエンバインディングを使った方法で、具体的な条件文を書く必要があります。
また、シーケンスを使って順番にイテレートする場合もオプショナルパインディングを利用できます。以下の例のようにfor case let value? in sequence
と書くと、オプショナルパインディングを使ったループができます。
for case let value? in sequence {
print(value)
}
これでオプショナルパインディングに問題がないことがわかります。カードを消してみると、以下のように書きかたが少し違いますが、同じことができます。
if let value = optionalValue {
print(value)
}
これはバリューがスコープ内に入ってくることで、エラーとなっていた問題を解決しています。最後に、guard let
を使ってオプショナルバインディングができることも確認できます。以下のように書くことで実行できます。
guard let value = optionalValue else {
return
}
print(value)
よかったですね、これで問題なく動作しました。 イフレット、つまりオプショナルバインディングが使われる場合ですね。フォーブも返されません。そのあたりがポイントです。次にセルフの話を見ましょう。さっき余談で話しましたが、キャプチャーした後にセルフが省略できるということです。暗黙的なセルフのことで、ウィークセルフキャプチャーをした後、セルフにアクセスするときに、セルフ.を求められていたのが省略できるという話ですね。
アンラップしたセルフに対してセルフが省略できるようです。これを理解するのに少し時間がかかるかもしれませんね。既にショートハンドを使ってアクセスしている場合、ガードレットのショートハンドができるので、普通に使われますが、セルフの省略を理解しなければなりません。
オプショナルバインディングとシャドウイングに比べ、オプショナルをキャンセルする方がより良いかもしれませんね。キャプチャリストの中でそうしたいという意図があるのでしょう。具体例として、インポジサイクルコードのタッチアリセンセルフからアンタパンドライコールが許されるようになりました。SE-026でこれがそうなりました。
キャプチャリストがなければセルフを書かないと暗黙のキャプチャが発生します。これをタッチアリセンと書くとセルフが省略されます。キャプチャリストの改良が進んでいるので、いくつかのコードで試してみましょう。
たとえば、ウィークセルフを使う場合、プリントエッグを使うときにウィークセルフがあるとエラーになるかもしれませんが、ガードレットセルフを使うと大丈夫になるのです。これがまだ実装されていないときもありますが、アクセステッドがオンリーされたときには効果が出るでしょう。
セルフの省略ができるとより便利ですが、すべてのタイミングでそうなるわけではありません。将来的にはセルフ省略の機能が標準になるかもしれませんが、現在はまだ移行中です。
また、ストラクトの場合だとセルフの省略がうまくいくことがあります。ストラクトは循環参照がなく、コピーされるため、キャプチャーされる動きも異なるのです。これにより、コードの見通しが良くなります。 キャプチャリストが存在すると、ついついキャプチャリストに書いてしまってコピーされたりすることがありますね。これもわかりづらいですよね。ちなみに正確な言葉かわかりませんが、キャプチャリストに書くことをキャプチャーと言います。たとえば、let y = 1
といった具合に書くことで、その値がキャプチャされます。その際に複製が渡されていきます。
キャプチャしなかった場合は、オリジナルのy
がそのまま使えるようになります。これを「フローティングオーバー」と呼ぶことがあるようです。ただ、この呼び方が正確かどうかは自信がありません。調べてみる必要があるかもしれません。
例えば、クロージャにおいてlet y = 1
とキャプチャリストに書かない場合について、キャプチャリストの概念を理解しておくことが大切です。また、キャプチャリストに書かれた値がクロージングオーバーでどう反応するかも確認する価値があります。クロージングオーバーは、そのままの変数をキャプチャリストに書かずに渡せる概念です。
具体的には、参照渡しとどう関係があるかも重要です。参照渡しになるかどうかは、アドレスを見ればわかりますが、放送中に確認するのは少々難しいかもしれません。実際に参照渡しであることが多いですが、必ずしも完全にライトバックではないこともあります。コピーインコピーアウトと呼ばれることもあり、昔はライトバックと言われていたこともあります。
クロージングオーバーでリセットが付いた変数を扱う場合、参照渡しになっているかどうかは重要です。参照渡しであれば、特定のタイミングで反応するはずです。ただし、マルチスレッドの環境では同時進行で検査しながらセットする必要があります。それによって制御できるコードを書くことが重要です。
リセットを協力して変更する必要がありますし、その場合キャプチャリストで取ることで安全性を確保することが安心です。クロージングオーバーをしないといけない場合もありますが、なるべく理想論にとらわれず、現実に即した実装をすることが肝要です。
以上で今日の勉強会は終わりにします。お疲れ様でした。