【Swift】Optional型のアンラップの方法

#Optional\<Wrapped>型のアンラップ

Optional\<Wrapped>型は値を持っていない可能性があるので、
Int型やString型と同じように扱うことが出来ません。


そこでOptional\<Wrapped>型が持つ値に対する操作を行うためにはどうすればいいのかというと、
**Optional\<Wrapped>型のアンラップ**を行う必要があります。

主に使われるアンラップの方法は、
**・ オプショナルバインディング
・ ??演算子
・ 強制アンラップ**
の３つになります。

##オプショナルバインディング
オプショナルバインディングとは、条件分岐文(if)の条件に
Optional型の値を指定します。

型の中身に値が入っている時のみif文内の処理を実行することができ、
Optionalの中身の値に直接アクセスすることができます。

オプショナルバインディングは、**if-let文** を用います。
Optional\<Wrapped>型の\<Wrapped>の部分は\<Int>や\<String>が入ります。

```swift

if let 定数名 = Optional<Wrapped>型の値 {
   値が存在する時に実行される箇所
}
```

どういう意味かというと、
Optional\<Wrapped>型に値が入っていた時、
「if let 定数名 = 」 の定数名の部分にOptional\<Wrapped>の値が代入されます。

この時、**定数のスコープはローカルスコープ**なので、
if-let 内でしか利用することができません。

また、Optional\<Wrapped>の中に値が入っていない(=nilの時)は
if-let 内の処理を実行せずに終わります。
下記は変数aに値が入っていなかった時の処理になります。

```swift

var a: Int?   // Optional<Int>型
var b: Int = 0   // Int型 

// 変数aに値が入っていたら、a の値を test に代入し { } 内の処理を実行  
if let test = a {   // 今回、変数a の値は nil
    b = test + 10   // 実行されない
}

print(b)   // 0
```

変数aの中には何も値が入っていないので if-let 文の中は実行されず、
変数bの値は0のままです。
なので、print(b)の結果は0になります。

次に、変数aに10を代入した時の処理になります。

```swift

var a: Int?   // Optional<Int>
var b: Int = 0   //Int型 
a = 10

// 変数aに値が入っていたら、a の値を test に代入し { } 内の処理を実行  
if let test = a {   // 今回、変数a の値は 10 つまり test = 10
    b = test + 10   // 実行される  (b = 10 + 10)
}

print(b)   // 20
```
今回のように、Optional\<Int>型の中に値が入っている時、
すなわち、Optional\<Int>型の中にnilが入っていなかった時は、
Optional\<Int>型の中身を利用することが出来るということになります。

オプショナルバインディングを使えば予期せぬnilに遭遇せず
安全なプログラムを組むことができます。


##??演算子
Optional\<Wrapped>型に値が存在しない場合のデフォルト値を指定するための演算子です。
??演算子を使えば、オプショナルバインディング同様、
nilによるアプリエラーが発生する確率がかなり下がると思います。

??演算子は、左辺にOptional\<Wrapped型>、右辺にWrapped型の値をおきます

```swift

let optionalString: String? = "こんにちは"   // Optional("こんにちは")
let message = optionalString ?? "おはよう"   // こんにちは
```

`let message = optionalString ?? "おはよう"`の部分が？？演算子になります。
左辺(??の左側)は、Optional\<Wrapped>型（今回はOptional\<String>型）
右辺(??の右側)は、Wrapped型の値（今回はString型）

もしoptionalStringの値がnilだった場合は、
デフォルト設定された「おはよう」が定数messageの中に入る。

```swift

let optionalString: String? = nil   // nil
let message = optionalString ?? "おはよう"   // おはよう
```
一つ注意しなければならないのは、
？？演算子はOptional型をアンラップするためのもなので、
messageの型はOptional\<String>型ではない通常のString型です。

Optionalが関わっているので、一瞬Optional\<Wrapped>型かと思ってしまいます・・・。

##強制アンラップ
強制アンラップは、その名の通り強制的にOptional\<Wrapped>型から値を取り出す方法です。
便利な機能ですが、強制的なので値が存在しなかった場合は実行時にエラーになってしまいます。

強制アンラップは！演算子を使用します。

```swift

①
var a: Int? = 2   // Optional(2)
var b: Int? = 2   // Optional(2)
a! + b!   // 4

②
var c: Int? = 2   // Optional(2)
var d: Int?   // nil
c! + d!   // 実行時エラー
```

一つ目は、Optional\<Int>型だった変数aと変数bを強制的にアンラップし足しています。
アンラップした後なので、計算結果の4は、Int型になります。

二つ目は、変数dがnilの状態で変数cと変数dを足しています。
この時、**文法的には特に問題はないのでコンパイルはできますが、
実行中にエラーが発生し強制的にアプリが終了します。**

エラー内容：Fatal error: Unexpectedly found nil while unwrapping an Optional value
和訳：致命的なエラー：オプション値のアンラップ中に予期せずnilが見つかりました

今回は、`c! + d!`のd！でnilが見つかりエラーが発生しています。
このように強制アンラップは記述は少なく楽に見えますが、
自分の予期せぬ箇所でエラーが発生する可能性が増えると思います。

なので、強制アンラップを利用する箇所は、
**確実にnilが入ることがない箇所でのみ使用する方がアプリ的にはいいのかなと思いました。**
(強制アンラップばかり使っていたので反省します・・・。)

##暗黙的にアンラップされたOptional\<Wrapped>型

先ほど、Optionalのアンラップの方法を３つ紹介しました、
意外と知られていなさそうな暗黙的アンラップについてもメモがてら紹介します。

まず、アンラップうんぬんの前に、
Optional\<Wrapped>型を宣言する時はみなさんどうされていますか？

以前に私の記事でも紹介しましたが、
大体の方が？や！を使用した宣言方法だと思います。

```swift

let a: Int?   // Optional<Int>
let b: Int!   // Optional<Int>
```
ここでふと、？と！の違いってなんなの？と思ったのですが皆さんはご存知でしょうか？
結構知らないで使っている人も多いのではないですかね・・・？（自分だけかも）

結構調べた結果やっと答えを見つけました！
結論から言いますと、
？は、**通常のOptional\<Wrapped>型であるWrapped？型**
！は、**暗黙的にアンラップされたOptional\<Wrapped>型であるWrapped！型**とのことでした。


結局よく分からん。(笑)

ということなので色々試して調べてみました！

まずはじめに型から調べてみました。

```swift

let a: Int!   // Optional<Int>
let b: Int?   // Optional<Int>
```

もちろん両方ともOptional\<Int>型でした

念のため別の方法でも確認をしました。
何をしたかというと、
Weapped！型をWrapped？型に代入し、Weapped？型をWrapped！型に代入しました。

```swift

let a: Int! = 1   // Optional<Int>
let b: Int? = 2   // Optional<Int>

let c: Int? = a   // 1
let d: Int! = b   // 1
```

変数a：Wrapped！型を、変数c：Wrapped？型に代入
変数b：Wrapped？型を、変数d：Wrapped！型に代入しております。

特にコンパイルエラーなども実行時のエラーもなかったので、
完全に両方共Optional\<Int>型なのは確認しました。


次に、本命のアンラップについて調べてみました。

暗黙的にアンラップされたOptional\<Wrapped>型というくらいなので、
計算する時に強制アンラップしなくていいのかなー？
なんて軽い気持ちで計算してみました。

```swift

let a: Int! = 1   // Optional(1)
a + 1   // 2
```

なんと、Wrapped？型は`a! + 1`のように強制アンラップしなければならなかったのに対して、
Wrapped！型は`a + 1`と強制アンラップしなくてもエラーが起きませんでした。

では、nilの場合はどうなるか検証

```swift

let a: Int! = nil
a + 1   // 実行時エラー
```

nilが入っている場合はWrapped？型と同じ挙動でした。

暗黙的にアンラップされるOptional\<Wrapped>型( = Wrapped！型)は、
**アクセスするたびに毎回自動で強制アンラップされるらしいです。**

つまり、`Int!`のようにOptional\<Int>型の宣言すると
通常のInt型のnilが代入できるバージョンというイメージですかね。

違いはなんとなくわかりましたが、
！と？どちらがいいのかは正直よく分かりません・・・。

個人的には、？を使う方が強制アンラップを明示的に行わなければならないので、
多少はコードの把握がしやすいかな？とは思いました。

絶対に言えることは、
強制アンラップや暗黙的アンラップは乱用しない方がいい！ということです。

**nilのせいで実行中にエラーが発生するのは困るので、
オプショナルバインディングや？？演算子を使う方がいいかなと思いました。**

以上、長くなってしまいましたが最後まで読んでいただきありがとうございました。