先日に眺めた オプショナルバインディング
に複数の条件を組み合わせて使う話でもう少し細かく見ていけそうなところがあるので、まずはそこから始めてみますね。それをひと通り見終えたとしたら、引き続いて オプショナル
を活用した自動的な強制アンラップ
について確認していこうと思ってます。どうぞよろしくお願いしますね。
今回はゆめみ社外に向けた参加者公募もありまして、ゆめみの外の人も招いた開催になります。
—————————————————————————————— 熊谷さんのやさしい Swift 勉強会 #169
00:00 開始 01:16 オプショナルバインディングと条件を複数記載 02:18 オプショナルな値の2通りの書き方 03:56 オプショナルバインディングを終えた値を隣で使える 05:23 オプショナルバインディングが生きる場面 07:40 オプショナルバインディングを使わない書き方 10:13 オプショナルバインディングの嬉しいところ 12:03 exit 関数は Darwin.C が必要 13:16 今は if で where は使えない 14:08 switch では where を使える 17:26 カンマは複数のパターンを記載するのに使うもの 19:30 複雑なエラーになる理由は評価式パターン 21:58 複雑な式での評価式パターン 22:38 switch のパターンにリテラル以外を指定可能 25:03 オプショナルバインディングと条件の記載順について 25:54 ここまでのおさらい 26:47 スコープを狭めるのにも役立つ 31:31 段階を踏んで書くよりわかりやすいかも 31:50 クロージング ——————————————————————————————
Transcription & Summarize : 熊谷さんのやさしい Swift 勉強会 #169
では始めていきますね。今日も引き続きオプショナルについてのお話です。オプショナルについては以前から延々とやっていて、いずれ動画の公開が追いついてくるかなと期待しています。追いついたら、その動画もぜひ見てください。
さて、前回は複数のオプショナルバインディングの条件判定についてお話しました。これはif文の複数の条件判定についてですね。複数の条件判定というテーマです。前回は簡単なところをカバーしましたが、今回は少し難しい内容に入ると思います。とはいっても、特に緊張する必要はありません。理解していればそれなりに難しいこともできるということです。複数の条件が書けるという話を中心に進めていきます。
たとえば、flagA
がtrueで、flagB
がtrueの場合などです。flagA
とflagB
があったときに、if flagA { ... }
のように条件を判定できます。さらに本題に入ると、これまで見てきたように、オプショナルバインディングも使えるという話です。
たとえば、value1
がInt
型のオプショナルとして存在するとします。少しややこしい書き方ですが、これがInt
のオプショナルとしてある場合、以下のように書きます。
if let value1 = optionalValue1, let value2 = optionalValue2 {
// ここでvalue1とvalue2を使う
}
このように複数のオプショナルバインディングを一つのif
文で処理できます。これができるというのが今回のテーマです。さらに、3行目と4行目のコードは同じ意味合いだという話がありましたが、それは今は詳しく説明しません。ただ、これが意味するところを理解できるようになると、Swiftの言語仕様についてかなり深く理解していると言えると思います。
今後、なぜ同じ意味になるのかがわかるようになってきたら、Swiftの言語力が相当高いという判断基準になります。もちろん、これは個人的な意見ですが、そういう人はアプリケーションを作る際にも他の知識があるとさらに役立つでしょう。
言語力というのは非常に大事なものです。日本語でも、難しい仕事をするためにはしっかりとした言語能力が必要ですよね。プログラミング言語も同じで、基本をしっかり理解しておくことが大切です。
以上のように、3行目と4行目のコードは少し難しい部類に入るので、今は詳しく考えなくて大丈夫です。また、オプショナルバインディングとして複数の条件を処理できるという点が前回のお話でした。今回はそのあたりの面白い特徴をさらに見ていきたいと思います。 例えば、変数 x
や y
にどう対応するかを見ていきましょう。ここで重要なのは、左から順番に評価して満たされたら右に進む、という評価の仕方です。例えば、y
をオプショナルバインディングで処理する場合、if let y = optionalY, y.bitWidth >= 8
といった条件を加えることができます。こうすることで、y
のビット幅が8以上という条件も満たすことができます。これにより、さらに複雑な条件を記述できますね。
オプショナルチェーニングも便利です。例えば、v2?
に値があった場合、そのビットを取り出すときにオプショナルチェーニングを使えます。これを使うことで、可能性が広がります。ただし、オプショナルチェーニングがすべての状況に対応できるわけではありません。たとえば、パラメータに渡すような場合、オプショナルチェーニングだけでは対応できないことがあります。
具体例として、y
の値が16進数表記で1桁のときという条件を考えてみましょう。この条件もオプショナルバインディングで処理できますが、従来の強制アンラップを使うと、nil
の場合にクラッシュする危険があります。オプショナルバインディングと併用することで、nil
の場合は評価が行われないため、このようなリスクを回避できます。
さらに、もし y
がオプショナルではない場合、例えば let yString = String(y)
といったイニシャライザーを使って対応できます。このとき、yString.count == 1
のような条件を追加できます。ただし、v2
がオプショナルのままだと、オプショナルを強制的にアンラップする必要があります。これを忘れるとエラーになりますので注意が必要です。
これを整えたコード例を示すと以下のようになります。
if let y = optionalY, y.bitWidth >= 8, let yString = String(y), yString.count == 1 {
// ここに条件を満たした場合の処理
}
このように、オプショナルバインディングとオプショナルチェーニングを適切に活用することで、安全かつ柔軟なコードを書くことができます。 オプショナルのチェイニングについての話が続いています。Swiftではオプショナルチェイニングを使うことで、コードをシンプルに書くことができます。例えば、オプショナルな値を安全に扱うために、if
文の中でオプショナルバインディングを行うことで、必要な値がnil
かどうかをチェックし、問題がなければその値を使用するという手法があります。
具体的な例を挙げると、オプショナルバインディングを使わない場合、次のように複雑な表現になることがあります。
if let count = optionalValue?.count {
if count == 1 {
// 何か処理
}
}
オプショナルチェイニングとオプショナルバインディングを併用することで、以下のようにシンプルに記述できます。
if let count = optionalValue?.count, count == 1 {
// 何か処理
}
昔はSwift 2の時代には、オプショナルと具体的な値の比較ができなかったようですが、現在のSwiftではこれが可能になっています。
さらに、if
文の中で連続して条件を書くことで、複雑な処理を回避することもできます。以下のように、複数の条件を1つのif
文で扱うことができます。
if let a = someOptionalA, let b = someOptionalB, a == b {
// 何か処理
}
この方法を知ることで、コードが見やすくなり、状況に応じて適宜使い分けができるようになります。もちろん、状況によっては12行目のような書き方のほうが見やすい場合もあります。
要するに、両方の書き方を知っておくことで、より状況に応じた、わかりやすいコードを書くことができるようになります。覚えられる人は、これらのテクニックを学んで帰ると良いと思います。 ちなみに、exit
が出ているのは、exit
は Cライブラリと標準ライブラリに定義されているので、これがインポートされていないだけですね。Mac環境では Darwin
をインポートすると C環境が入るので、これでビルドエラーが出なくなります。ちなみに、DarwinというのはOS名で、Darwin OS互換の MacOS X みたいなものです。この辺はまだわからないかもしれませんが、そういうことです。
ここにif文やオプショナルバインディングと条件判定をif文で併用していけるような箇所がありますが、もう少し話せることがある人や面白いことがある人はいませんか?特に難しいところまで含めて使い方によっていろいろありますよね。
昔は where
句が使われていたのですが、例えばこれは昔の書き方です。現在では where
を使うとコンパイルエラーになります。where
の代わりに if
文を使うようになっています。個人的には where
が好きだったのですが、どうして廃止されたのかは分かりません。原稿仕様では、次のように基本的なことを書いて、y
を取り出して、その y
が特定の条件を満たす場合などの書き方が結構好きでした。
短絡評価との兼ね合いがあって、どこまでを短絡評価とすべきかというのが分かりにくくなってくる問題があったのかもしれませんね。switch
文の場合は、これができます。例えば、switch
文を使って Optional
パターンにwhere
句を使う例を書いてみます。
switch value {
case let y? where y > 8:
print("Value is greater than 8")
default:
print("Default case")
}
この switch
文の場合、すべてのパスで y
が定義されているわけではないためコンパイルエラーとなる場合があります。また、ブール値は Int
のオプショナルとはマッチしないというエラーも出ることがあります。これはアンラップしないといけないからです。
もし変換できなかった場合の処理を追加しないといけない場合、次のような感じです。ただし、この部分でどうしてコンパイルエラーが出るかについては、もう少し詳しく見ていく必要があります。
if let unwrappedY = y, unwrappedY > 8 {
print("Unwrapped value is greater than 8")
} else {
print("Unwrap failed or value is not greater than 8")
}
なぜこの部分で引っかかるのかについて、もう少し詳しく調べる必要がありそうですね。 とりあえずここまでのコードを別の場所に移動して、整数で受け取る形にします。これが文字列でないと、うまくいかないですからね。なので、文字列に変換します。この文字列のカウントを取得すると、それが普通に整数型になりますよね。整数型同士の比較で問題ないでしょう。もし何か気づいたことがあれば、コメントとかで教えてもらっていいですね。
この部分をコメントアウトするかどうかですが、実際のところはコメントアウトしないほうが良いかもしれません。コンパイルエラーが出ないように一度コメントアウトして、問題が解決できるか試みます。カンマを使うとエラーが出ますね。これをカンマにすると、非常に複雑なエラーが返されます。カンマが間違っていると気づける人はいないことはないでしょうけれど、通常は難しいですね。
プログラムが &&
演算子が必要だと言っていますが、これは短絡評価の関係で必要になるからです。短絡評価とは、最初の条件が偽であれば、以降の条件を評価しないというものです。
if
文のカンマの部分をコメントアウトしましたが、これを修正しておきましょう。if
文と同じ書き方ができないのは、Swiftの言語仕様のためです。このエラーがなぜ細かくなっているのかも気になります。この部分を式パターンとして評価したのか、これはイントのオプショナル型だから、こちらの評価がブール型なので、オプショナル型とブール型を一致させようとしてエラーが発生しています。
式パターンという言葉に馴染みのない方も多いと思いますが、パターンマッチングに関する動画が公開されていると思います。パターンマッチングの概念については、その内容を見ると理解できるでしょう。式パターンとは、この値とこの値が一致するかどうかを比較するパターンマッチングの一種です。 全体が評価される部分ですね。ここは問題なく動くはずです。Int
のオプショナルは、アンラップしないといけません。多分、ここで言っているのは、オプショナルをアンラップする必要があるということです。
例えば、オプショナルのアンラップには!
を使えば、エラーが出なくなります。次に進みましょう。途中でブール値とInt
が比較できないというエラーが出ましたね。ここまで進んできましたが、つまり、オプショナルとそうでない値をパターンマッチングしようとしているのです。この場合、どちらかを選ぶ必要があります。
ですから、== 1
などの比較ではなく、v2
に入っているInt
の値とy
を比較するのです。このy
はどこで定義されているのでしょうか?もし、y
がどこかで定義されていて、それを使いたいだけなら、このy
を文字として使って、条件をパターンマッチさせることができます。
わかりやすくするための例ですが、これは少し複雑な評価をしているように見えますね。便利ですが、注意が必要です。例えば、C言語のスイッチ文はリテラルしか受け付けませんが、Swiftのスイッチ文は変数を受け付けることができます。変数を動かしながら同じスイッチ文で様々な条件にマッチさせていくことが可能です。
ここで、y
と一致したら何をするか、といったことも書くことができます。このy
が変数なら、いくらでも書き換え可能で、そのため、マッチの仕方がランタイムで変わることも可能です。こういった機能は非常に強力で面白いものです。
話が少し逸れましたが、元に戻しましょう。条件として指定する部分にカンマ(,)を書いてしまうと、スーパーマッチみたいになってしまうので、条件を示すために、きちんとコロン(:)を使わないといけません。そうでないと、ちゃんと動かないことがあります。
例えば、&&
(アンド)を使って条件を組み合わせることも可能です。この場合、最初に指定された条件が満たされれば、その後の条件が評価されるという短絡評価が適用されます。これくらいでおおむね大丈夫でしょうか。
条件式を並べてオプショナルバインディングを使ったり、フラグの判定を行ったりできます。例えば、fc
というフラグがあるとしたら、if
文のように条件を組み合わせて評価することが可能です。すべての条件が満たされた場合のみ次の条件が評価されるので、この短絡評価の仕組みを覚えておけば大丈夫です。
大体理解できたら次に進みましょう。オプショナルバインディングや条件式の追加は、このように柔軟に対応できます。例えば、Int
型の変換に失敗する可能性のあるイニシャライザーを用いる場合、それが成功か失敗かによって、オプショナルバインディングが成立するかどうかが変わります。
同様に、複数の条件を合成して評価することで、非常に柔軟なプログラムが書けるようになります。右側がランタイムで決まる場合でも即席で実行した結果を評価することができます。これは非常に便利です。
以上で、この部分の解説を終わりますが、他に質問やコメントがあればどうぞ。 これができなかったとすると、事前に受けといて条件を満たしていく。ただし、そうすると if
文が終わった後も使えちゃう。そこがちょっと厄介なところなんですよ。そこ、良い例だから紹介しておこう。要はね、何が言いたいかというと、こうやってこれでもう動くじゃないですか。ここで if
文が終われば、もうねファーストナンバーとかは使えないわけですよ。本当はエラーになりますよね、ファーストナンバーがないよっていうふうに言われる。
ただこれがもしできなかったとすると、この2つのオプショナルバインディングを外でやらないといけなくなってくるわけですよ。こんな感じね、こう書いておこうかなというふうにすると、動きはすぐちゃんとね、何の問題もなく動きはするし、何も間違ってはいない。そこは大事なところなんですけど、大きな違いはね、何が起こったかというと、これはオプショナルバインディングを使ったからですね。
だから、事前に変換できるかどうかをいろいろやっておかないといけないわけです。けれど、ガードとかでね、今回は省略して強制的にアンラップしたほうがいいかな。でもこうすると動いてくるわけですけど、重要なところとしては、ここ休業目がちゃんと動くっていうところがさっきのオプショナルバインディングを if
文の中で使うのとは大きな違いがあって、状況にもよりますけど、さっきの例で言うならもう7行目以降ファーストナンバーはいらないんですよ。なのにそれが使えてしまうっていうのは、もしかすると、うっかり間違って使っちゃうみたいなことが起こり得る可能性が増えてくるということです。
間違いの可能性が増えてきたりするので、できるだけ変数や定数っていうのは最小限のエリアで使える範囲を狭めて、それ以降は使えないようにするっていうのが、気を使っておくと安定的なコードに繋がっていくんです。そういう意味で見たときに、この書き方だと、休業目いらないところ、休業目以降その中でもファーストナンバーやセカンドナンバーが使えちゃうというところが、ちょっと注意したいポイント。
そこも含めて、さっきのオプショナルバインディングが if
文の中で使えるということの有意義さを意識できるようになると、テクニカルスキルがアップできる感じかな、いい感じですね。これさっきのほう、これをスコープ閉じ込めたときって2ブロックで、ここまでですよっていうのを明確にするとどうするか、使えなくなりますよね。または、これ関数で定義されていたとしたら、これはこれでいいわけですよね。アクションの中だけの話になるんで、こうやって12行目には影響しないし、この程度だったらそんなに難しいこと考えなくても、こういう意味でも関数を役割の中で最低限のコードで収めていけば、これはそれであり。
こんなふうにいろいろとやり方はありますけど、要は変数のスコープは最小限に押さえていくっていうね、そういった意識も大事で、その上でさっきの今日紹介したこの方法、これも役立っていくよっていう感じですかね。下の例でそうやって分解していたこともできるけど、上のほうがわかりやすいよねっていう例かな。下のほうがもちろんわかりやすい状況とかもあったりするんで、その辺りは両方知っておくと良いことがありますねっていう感じでとらえておけばOKですかね。
じゃあ2時間になったので今日はこれぐらいにしておきましょう。また引き続きオプショナルについてのお話、いくつかあるので話していこうと思います。
はい、じゃあこれで終わりにします。お疲れ様でした。ありがとうございました。