[Swift 基本の型 第4回(第1部)] Optional型

f:id:KAFAppFactory:20200505102702j:plain

Swiftの基本の型 第4回(第1部)として、下記の「Swift実践入門」を参考に、Optimal\型について学習したので、備忘録としてまとめます。 (まとめていたら結構なボリュームでしたので、第4回は1部、2部に分けます。。。)

gihyo.jp

Optional型とは...

optional\型とは、 一言で言うなら、「値があるか空のいずれかを表す型」です。さらに言い換えると、nil という値がない状態を許容するかどうかです。

Swiftの定数や変数は基本的にnilを許容しませんが、nilを許容する必要がある場合はOptional\型を使用します。

例えば、次のように Int型を入力することが可能です。

例 )

let a: Optional<Int> = 1

これは

let a: Int? = 1

と書いたことと同じ意味になります。
ここで、IntInt?って形が似ていますよね?僕もここで混乱したのですが、IntInt?は全くの別物ですので注意してください! (StringIntのようなイメージです)

したがって、

let a: Optional<Int> = 2
let b = a * a 
// ↑はコンパイルエラーになります!

上のようにOptional型 に対して * を呼び出す事はできません。

Optional\型のアンラップ

Optional\型の値が持つWrapped型の値に対する操作を行うには、Optional\型の値からWrapped型の値を取り出す必要があります。

これはイメージなんですが、 Optional型という箱がある...と考えると理解がしやすいかと思います。 Optional型は箱なので、中身が入っている状態もあれば空の状態(nil)もあります。 例えば何か箱の中に物をしまっている時に、中の物を変えたい場合は箱から一度取り出す必要がありますよね? それと同じでOptional\型の値にアクセスしたい場合はOptional\型からWrapped型の値を取り出す必要があります。

このWrapped型の値を取り出す操作をアンラップといい、アンラップの方法は3つあります。

  1. 強制アンラップ
  2. オプショナルバインディング
  3. ??演算子

1) 強制アンラップ

強制とついているように、これは無理やりアンラップする方法になります。 無理やりアンラップしているため、もし仮に値が存在しない場合はエラーとなります。 (何事も無理やりは良くないですね...)

強制アンラップを行うには、!演算子を使用します。 次の例では、Int?型の2つの定数からInt型の値を強制的に取り出して、それらの和を取っている例になります。

例 )

let b: Int? = 1
let c: Int? = 1

b! + c! // 2

強制アンラップは値がないケースを無視したシンプルなコードを可能にしますが、一方で実行時にエラーとなる可能性があります。(そもそもnilを許容するためにOptional型を使用しているのに、nilとなったらエラーというのは本末転倒な気がします...)

ここで、参考に挙げている「Swift実践入門」からの引用ですが、良い文章であったので紹介させていただきます。

Swiftは、プログラムの誤りをできるだけコンパイル時に検出することによって安全性を高めるという設計思想を持つ言語であす。強制アンラップを多用することは、その思想に反してエラーの検出を実行時まで先延ばしにすることを意味します。

まったくもってその通りだと思います。したがって、値の存在がよほど明らかな箇所や、値が存在しなければプログラムを終了させたい箇所以外では、強制アンラップの使用は避けることが無難かと思われます。

2) オプショナルバインディング

さて、次の方法は強制アンラップに比べて安全に値を取り出す方法になります。

オプショナルバインディングでは、条件分岐文や、繰り返し文の条件にOptional\型の値を指定します。 値の存在が保証されている分岐内では、Wrapped型の値に直接アクセスすることが可能です。 オプショナルバインディングはif-let文を使用します。

例 )

let OptionalA = Optional("a") // String?型

if let a = OptionalA {
    print(type(of: a)) // OptionalAに値がある場合のみ実行
}

if-let文は上のようなフォーマットになっており、代入式の右辺にOptional\型の値を指定します。 Optional\型がWrapped型の値を持つ場合は、左辺の定数にWrapped型の値が代入され、if文に続く{}内の実行文が実行されます。値がない場合、実行文はスキップされます。

まとめると下記のような形をオプショナルバインディングと言い、条件としてオプショナルバインディングの型とは、異なる型へ代入を行います。

if let 変数名 = オプショナル型の変数 {処理}

3) ??演算子

次の方法は、値をそのまま取り出すイメージとは違い、Optional\型に値が存在しない場合のデフォルトの値を指定する方法になります。 nilのまま取り出すとエラーが発生してしまう場合を避けるために、別の値で取り出して実質的にnilを回避する方法になります。デフォルトの値を指定するには、中値演算子??を使います。

??演算子の式は、下記の例のように左辺にOptional\型の値、右辺にWrapped型の値をとります。

例 )

let optionalInt1: Int? = 1
let int1 = optionalInt1 ?? 3 //1

左辺のOptional\型が値を持っていればアンラップしたWrapped型の値を返し、値を持っていなければ右辺のWrapped型の値を返します。例では、??演算子の左辺にInt型の値1をInt?型の定数optionalIntを、右辺にInt型の値3を指定し、結果として左辺の値1を取得しています。

例 )

let optionalInt2 : Int? = nil
let int2 = optionalInt2 ?? 3 // 3

左辺のInt?型の定数optionalIntにnilが入っている場合は、結果として右辺のInt型の値3を取得します。

終わりに

今回、Swift 基本の型 第4回(第1部)としてOptional型の概要とアンラップについてまとめました。Optional型についてはもう少しだけ理解すべき内容がありますので、第2部でまたお会いしましょう!ではでは!