配列で学ぶOptional（配列でnilを表現する）

この記事Optional初心者向けです。

* Javaなどのnil(null)を知っている
* 配列を知っている
* Optionalはよくわからない

という方を対象にしています。
nil（何もないこと）を配列で表現する例と、それに対応するOptionalで表現する例を読むことで「Optional難しくないね」と感じてもらえればと思います。

## ないことを配列で表現する

```swift
class User {
    var id: String

    init(id: String) {
        self.id = id
    }

    func showId() {
        print(id)
    }
}
```

このUserインスタンスがあるかもしれない、ないかもしれない…

そんな状態をnil以外の方法で表現してみましょう。
例えば配列を以下のように使えば実現できそうです。

* 配列の要素が1つならある（nilではない）
* 配列が空ならない（nil）


```swift
// 値がある場合
let userOrNil: Array<User> = [User(id: "id")]
```

```swift
// 値がない場合
let userOrNil: Array<User> = []
```

上記では`Array<User>`と書いていますが同じ意味の`[User]`を使うことがほとんどですので、以降は`[User]`と書きます。


## 配列はUserではない

**これがとても重要です。**
当たり前のことですが、配列とUserは違うものです。

```swift
userOrNil.id // コンパイルエラーになる
```

コンパイルエラーになるので、nilに対してメソッドを呼び出せず、ぬるぽになりません！

## 値のあるなしを判定する

配列の要素数を数えれば値のあるなしを判定できます。

```swift
// 値がある場合
if userOrNil.count == 1 {
    print("値がある")
}
// 値がない場合
if userOrNil.count == 0 {
    print("値がない")
}
```

Userがあればidを表示し、なければ"no user"を表示してみます。

```swift
if userOrNil.count == 1 {
    let user = userOrNil[0]
    print(user.id)
} else {
    print("no user")
}
```

UserがあればshowId()を呼び出し、なければ何もしない場合以下のようになります。

```swift
if userOrNil.count == 1 {
    let user = userOrNil[0]
    user.showId()
}
```

Userがあることが確実であれば、条件判定せずいきなり呼び出すこともできます。
ただし値がなければクラッシュします。

```swift
userOrNil[0].showId()
```

## 値を取り出す

Userのid取得したいのですが、Userがあるかはわかりません。
そこで、userがあればidを含む配列、userがなければ空配列を結果とすることにします

```swift
let idOrNil: [String]
if userOrNil.count == 1 {
    let user = userOrNil[0]
    idOrNil = [user.id]
} else {
    idOrNil = []
}
```

Userが確実にあるとわかっているなら、配列に格納せず文字列で結果を取得しましょう。
ただし値がなければクラッシュします。

```swift
let id: String
id = userOrNil[0].id
```

Userがない場合、idを空文字列として扱えばいいという場合もよくあります。
この場合も配列に格納せず文字列で結果を取得しましょう。

```swift
let id: String
if userOrNil.count == 1 {
    let user = userOrNil[0]
    id = user.id
} else {
    id = ""
}
```

## ないことをOptionalで表現する

配列を使って「ない」ことを表現することができました。

次は配列ではなくOptionalで「ない」を表現します。
Optionalは

* 配列のように値を格納できる
* 配列と違い1個しか格納できない
* 配列より便利に書ける

ようなものと考えると理解しやすいです。

```swift
// 値がある場合
let userOrNil: Optional<User> = User(id: "id")
```

```swift
// 値がない場合
let userOrNil: Optional<User> = nil
```

配列の場合は`Array<User>`でしたが、Optionalの場合は`Optional<User>`となります。
ただ配列を`[User]`で表すように、Optionalは`User?`と書くことがほとんどですので、以降はこちらの書き方を使います。

### 追加要素

配列版の場合、Userを配列に格納するコードを書いていました。
しかしOptional版ではそのコードはありません。
Optionalの変数（定数）に通常の値を代入すると、自動でOptionalに包んでくれる機能があるためです。
値がある場合のコードは、以下のコードと同等です。

```swift
let userOrNil: Optional<User> = User?(User(id: "id"))
```


## OptionalはUserではない

**これがとても重要です。**
当たり前ですが（そうでもないかも）、OptionalとUserは違うものです。

```swift
userOrNil.id // エラーになる
```
コンパイルエラーになるので、nilに対してメソッドを呼び出せず、ぬるぽになりません！

## 値のあるなしを判定する

値のあるなしは以下のように判定します。

```swift
// 値がある場合
if userOrNil != nil {
    print("値がある")
}
// 値がない場合
if userOrNil == nil {
    print("値がない")
}
```

**nilを使ってるじゃん**というツッコミがありそうですが、nilという単語はあります。
メソッドを呼び出すとクラッシュするnilではないので許してください🙇‍♂️

Userがあればidを表示し、なければ"no user"を表示してみます。

```swift
if let user = userOrNil {
    print(user.id)
} else {
    print("no user")
}
```

UserがあればshowId()を呼び出し、なければ何もしない場合以下のようになります。

```swift
if let user = userOrNil {
    user.showId()
}
```

配列版では、要素があるか確認して、取り出して使用しました。
Optionalでは確認と取り出しを一度に行う `if let var = optional` という書き方ができます。

Userがあることが確実であれば、以下のように書けます。
`!`で値を取り出し（配列版の[0]と同等）、メソッドを呼び出します。
値がなければクラッシュします。

```swift
userOrNil!.showId()
```

### 追加要素

配列版ではなかった要素として
**値があれば取り出して実行**
**値がなければ何もしない**
を簡単に書く方法があります。

```swift
userOrNil?.showId()
```

処理内容は`if let`で値を取り出し`showId()`を呼び出すコードと同じです。

## 値を取り出す

Userのid取得したいのですが、Userがあるかはわかりません。
そこでuserがあればidをOptionalに入れ、userがなければ(Optionalの)nilにしましょう。

```swift
let idOrNil: String?
if let user = userOrNil {
    idOrNil = user.id
} else {
    idOrNil = nil
}
```

Userが確実にあるとわかっているなら、通常の文字列で結果を取得しましょう。
ただし値がなければクラッシュします。

```swift
let id: String
id = userOrNil!.id
```

Userがない場合、idを空文字列として扱えばいいという場合もよくあります。
この場合も通常の文字列で結果を取得しましょう。

```swift
let id: String
if let user = userOrNil {
    id = user.id
} else {
    id = ""
}
```

`?:`演算子のような`??`演算子を使うと、上記の処理はもっと簡単に書けます。

```swift
let id: String
id = userOrNil?.id ?? ""
```

### 追加要素

配列版ではなかった要素として
**値があれば取り出す**
**値がなければnilになる**
を簡単に書く方法があります。

```swift
let idOrNil: String?
idOrNil = userOrNil?.id
```

処理内容は`if let`で値を取り出し、`user.id`または`nil`を代入するコードと同じです。

## 補足

`let userOrNil: User?` などと書いていますが、Optionalの変数にOptionalとわかる命名をする慣習はないです。
通常は`let user: User?`のように書きます。
また以下のように名前が被っても問題ないので書き方で困ることもないはずです。

```Swift
if let user = user {
    print(user.id) // このuserはOptionalではない
}
```


## あとがき

慣れていないうちは、
`Optional`は`String`（などの中身）ではないからメソッドを呼び出せないことを忘れたり、
何か特別なすごい機能と身構えたり、
そんなところで難しいと思ってしまう人を見かけました。

この記事でOptionalに対する気負いが減ることを願っています🙏