Swift

【Swift】optional型とnil,if let と guard let とは?|アンラップの違いやメリット解説

記事内に商品プロモーションを含む場合があります

Swiftの勉強を始めて最初につまずくであろうoptional型
nilと何が違うの?
if let, guard letはいつ使うの?

この記事ではSwiftにoptional型とnilの違い,そしてif let, guard letの使い方を,まとめて紹介します!

Swiftで開発していてわからなくなった際に,見に来てくれると嬉しいです!

nil と optional型の違い

基本的な概念

nilは文字通り,値が存在しないことを示す特別な値になります.
若干ニュアンスは異なりますが,noneと似たような感じですね.

ではnilを扱う際に出てくるoptional型.
これは一体何なんでしょうか?

optional型はズバリ,nilを扱うことができる型になります.
もう少し詳細に説明すると,変数が「値を持つかもしれないし,持たないかもしれない」ことを示すための型
つまりオプショナル型を使うことで,nil(値がないこと)を安全に扱うことができるようになります.

実際にnilの安全な使い方

nilを配列で使用する場合を考えます.

var optionalValue: Int? = nil
var optionalArray: [Int?] = []

// nilを配列に追加
optionalArray.append(optionalValue)

print(optionalArray) // 出力: [nil]

配列はoptional型で宣言しているため,nilを代入することができます.

一方で下記の例を見てみましょう.

var optionalValue: Int? = nil
var nonOptionalArray: [Int] = []

// optionalValueがnilの場合、コンパイルエラーが発生
nonOptionalArray.append(optionalValue) 
// エラー: Cannot use optional value 'optionalValue' in the 'append' call

この例では,配列をoptional型で宣言していないために,
nilを配列に追加しようとした際にエラーが発生
しています..

このようにoptional型はnilが発生しうる場合に用いることで,エラー・クラッシュを防ぐことができます.

アンラップ/unwrap

アンラップ/unwrapとは?

先程までnilを代入・追加する例を示してきましたが,
アンラップは,逆にオプショナル型の変数から実際の値を取り出すプロセスを指します.
つまり,オプショナル型は値が存在するかもしれないし、存在しないかもしれないことを表現するための型であるため,nilが含まれている可能性があります.
そこでアンラップを行うことで,オプショナルに格納された値を安全に使用できるようになるのです.

安全性・堅牢性と可読性が上がるわけですね!

if let と guard letの違いは?|アンラップの方法

アンラップする方法として代表的なものに,if let と guard letが存在します
これらの2つの違いは,主に処理のタイミングの違いです.

if letを使ったアンラップは,下記のようになります.
else文はなくても構わないため,nilじゃない場合に処理を行うといった認識ができますね.

var optionalValue: Int? = 42

if let value = optionalValue {
    print("Value is \(value)") // 42と表示される
} else {
    print("Value is nil")
}
Swift

一方で,guard let を使ったアンラップは,下記のようになります.
if letと大きく変わりませんが,nilが入ってきた場合に例外処理を行っているような認識になります.

func processValue(optionalValue: Int?) {
    guard let value = optionalValue else {
        print("Value is nil")
        return
    }
    print("Value is \(value)") // 値が存在する場合にのみこの行が実行される
}
Swift

大きな違いはありませんが,
どちらの処理を行ったほうがコードがきれいになるのかを意識しながら,アンラップの方法を選択したいですね!

ちなみにこれら2つのアンラップは,オプショナルバインディングに分類されます.
少し異なるものに,オプショナルチェイニングというものも存在します.

struct Person {
    var name: String?
}

let person: Person? = Person(name: "Alice")

// オプショナルチェイニングでプロパティにアクセス
let personName = person?.name
print(personName)  // Optional("Alice")
Swift

?をつけてその時点で判定を行い,
途中でnilに遭遇した場合は,自動的にnilが返され、処理が終了するといった流れです.

Xcode上でエラーとなり,自動補完でとりあえず?をつけたこともあるのではないでしょうか?
optional型に対して,その時点で判定をしているのですね.

そのため,print(person?)といった使い方はできません.
print(person)としてoptional型で出力するか,if let や guard let などのオプショナルバインディングを使用して出力しましょう!

強制アンラップとは?

実はif let や guard let以外に,強制的にアンラップをする方法もあります.

var optionalValue: Int? = 42
let value = optionalValue! // valueは42になるが、optionalValueがnilの場合はクラッシュする
Swift

! をつけるだけですね笑
ただし,optionalValueがnilの場合,ランタイムエラー(クラッシュ)が発生します.
強制アンラップは避けるべき
ですね.

nilの場合に,固定値を代入したい場合は?|
nil-coalescing演算子

値がnilの場合も,他のある値を代入して処理を行いたい場合もあると思います.
その場合は,nil-coalescing演算子(??)を使ったアンラップで解決できます.

var optionalValue: Int? = nil
let value = optionalValue ?? 0 // optionalValueがnilの場合、0が代入される
Swift

これは例えば,
user.nameが存在しない場合に,Guestとするといったコードでも応用できますね!

struct User {
    var name: String?
}

let user: User? = nil
let username = user?.name ?? "Guest"
print(username) // "Guest"
Swift

おわりに

このブログでは,SwiftやFlutterなどの日々学びつつアウトプットしています.
また,間違いや改善点があれば,ご指摘いただけますと幸いです!