SwiftとOptionalについて

WithOne AdventCalendar 25日目(http://qiita.com/advent-calendar/2016/withone) 最終日です。

みなさん参加してくださってありがとうございました!
投稿先をQiitaにしたのは少しハードルが高かったかなと思いつつ、
来年もAdventarあたりでまたやりたいなあなんて思っています。


最終日はSwiftとOptionalのススメです。
最近流行りのNull安全な言語。
SwiftもNull安全な言語の一つです。

Null安全な言語といえば、
Python、Kotlin、TypeScriptなどは名前を聞いたことがある人もいるのではないでしょうか。
最近こんな記事も話題になりました。
null安全でない言語は、もはやレガシー言語だ - Qiita

Optionalを通じてSwiftの楽しさ、便利さについて、みなさんに伝わると良いなと思います。

※Swiftではnullをnilと言います


SwiftではOptionalと言う型が使えます。
Optionalとは、「nilを入れることのできる入れ物」を表します。

Swiftではnilを入れることのできる変数かどうかを
あらかじめ設定しないと、変数を作ることができません。

Javaの場合は以下のように書いた場合、
変数hogeにはいつかnullが入る可能性があります。
hogeを使うときには、常にnullの存在を考えなければならないです。

String hoge = "ほげ";  

Swiftの場合、nilを入れることのできる変数かどうかを、
あらかじめ指定しておく必要があります。
書き方は以下の通りです。

// nilを入れることができる変数
var hoge: String? = nil

// nilを代入することができない変数
var hoge: String  = "ほげ"

上下の構文の違いは、型宣言をしているStringの後ろに?がついているかいないかです。
Swiftでは?をつけることで、「この変数はnilを代入することが可能な変数ですよ」
ということを表しています。

ここでは詳しく説明しませんが、
OptionalはOptional<T>という一つの型です。
SwiftではこのOptional<T>を、?を使って簡単に書くことができるようになっています。

非Optional

?のついていないStringには、
nilを代入することができません。
この?が付いていない型を、非Optionalと言います。
非Optionalで宣言した変数にnilを代入しようとすると、
コンパイラがエラーにしてしまうのです。

もしnilになる可能性のある値を代入しようとする場合、
以下のようにデフォルトの値で初期化する書き方をすることができます。
これが結構便利です。

var hoge: String? = nil
var foo: String = "ふー"

// nilの入っている可能性のある変数を代入しようとするとき
// ?? をつけるとデフォルト値を指定できる
foo = hoge ?? "デフォルト"


このように非Optionalの値は、コーディング時にnilが入るかどうか、
他のメソッド中身等を確認したり、nilチェックをする必要がなくなるのです。

Optional

Optionalの型の場合は、値が入っているのか、nilなのかを確認する必要があります。
値が入っていることを確認し、
Optional型から中身を取り出すことをunwrap(アンラップ)と言います。

そもそもStringとString?は
StringとOptional<String>という異なる型になります。
このOptional<String>に入っているStringを使用するためには、
Stringの値をOptionalから取り出してから使用する必要があるのです。

Optionalからの値の取り出し方を以下に記載します。

var hoge: String? = XXXXX // nilかそれ以外かの何かが入っている

// hogeの中身をunwrapHogeに取り出してから使用する
if let unwrapHoge = hoge {
    print(unwrapHoge)
}

Swiftではこのif let 変数名 = Optional型の何か という書き方をよくします。
※let とはSwiftの定数の宣言を表します。varは変数の宣言です。

hogenilではない場合、String?型のhogeから中身が取り出され、
unwrapHogeに代入されます。
hogeの中身がnilだった場合は、falseとなり、このif文の中の処理は行われません。

また、hogeの中身がnilだった場合は、この後の処理を全て行わずにreturnしたいという時もあります。
そんな時はguard文を使用します。

var hoge: String? = XXXXX // nilかそれ以外かの何かが入っている

// hogeの中身をunwrapHogeに取り出して、nilだった場合は以降の処理を行わない
guard let unwrapHoge = hoge else {
    print(unwrapHoge)
    return
}

// その後の処理色々
print(unwrapHoge)


guard文は、
「設定した条件式に当てはまる場合のみ、
それ以降の処理を実行する」
ということを表す構文になります。

guard文の中では必ず、returnやbreakなど、
以降の処理を行わない旨の処理を記述する必要があります。

このようにして、Optionalの変数は、
値が入っている場合のみ使用されるよう作られているのです。

※中身がnilでも使用する方法はありますが
今日はここまで。。

最後

Optionalの使い方について少しだけ興味が湧いてきましたか・・?
nilの扱い方について少しだけ便利になるOptionalですが、
nilに全くならないというわけではありません。

Optionalの型をnilが入っていても使うことはできてしまいますし、
デフォルトの値を設定する例を出しましたが、
あの処理自体もきちんと考えてデフォルトを設定しなければ、
ただエラーの握りつぶしを行うことと同じことにもなるのです。

最後に、

Swiftはいいぞ!