#guard文 とは
条件不成立時に早期退出を行うための条件分岐になります。
if文と同じく条件式の結果であるBool型の値に応じた処理を行います。
ですがif文とは異なり、後続の処理を行うにあたってtrueとなっているべき条件を指定します。
guard文は、条件式がfalseを返す場合のみ{ }内の処理を実行し、
条件式がtrueを返す場合は{ }内の処理をスキップします。
また、{ }内の文では、guard文が記述されているスコープの外に退出する必要があります。
退出する方法は、returnを用いて退出します。
guard 条件式 else {
条件式がfalseだった場合の処理
return // guard文が記述されているスコープの外に退出する処理
}
結果if文でよくないか?と思いがちですが、
guard文にはguard文の良さがあります。
例として年齢をチェックするメソッドを作成します。
18歳以上か18歳未満かで処理を変えます。
(メソッドについての詳細は別記事で紹介する予定です。)
// if文を使った場合
func ageCheckIf(age: Int) {
if age >= 18 {
print("18歳以上なので閲覧可能です。")
} else {
print("18歳以下なので閲覧できません。")
}
}
// guard文を使った場合
func ageCheckGuard(age: Int) {
guard age >= 18 else {
print("18歳以下なので閲覧できません。")
return
}
print("18歳以上なので閲覧可能です。")
}
ageCheckIf(age: 10)
ageCheckGuard(age: 10)
ageCheckIf(age: 20)
ageCheckGuard(age: 20)
実行結果
18歳以下なので閲覧できません。 // ageCheckIf(age: 10)
18歳以下なので閲覧できません。 // ageCheckGuard(age: 10)
18歳以上なので閲覧可能です。 // ageCheckIf(age: 20)
18歳以上なので閲覧可能です。 // ageCheckGuard(age: 20)
文のボリューム自体は大体同じですが、
見やすさがguard文の方が見やすいかなと個人的には思います。
guard文についての説明ですが、
guard age >= 18 else
の部分で18歳以上かどうかチェックしています。
もしageが18未満だった場合はguard文の中に入ります。
guard文の中では、print("18歳以下なので閲覧できません。")
を実行後、
return
でスコープの外に退出しています。
どこまで退出するのかというと、guard文が存在するスコープの外まで退出します。
つまり、func ageCheckGuard(age: Int) {・・・}
の外までです。
guard文の条件式の結果がtrueだった場合は、
guard文の{ }内は実行されず、guard文以降の処理が実行されます。
つまり、guard文以降の処理は全て、
guard文の結果がtrueだった時の処理ということになります。
条件分岐でfalseの時だけこの処理をしたい!などの場面ではかなり使えると思います。
全てif文で記述するとネストしすぎて見づらくなる可能性もあります。
###退出の強制
guard文のelse節はguard文が含まれるスコープから絶対に退出しなければなりません。
スコープからの退出は強制されているのでコンパイラにチェックされております。
なので、{ }内にreturnがないとコンパイルエラーが発生します。
強制されているが故に、
guard文以降の処理はguard文の条件式が必ず成り立っていることが証明されます。
なので、先ほどの年齢チェックの例でも、
条件式がtrueだった場合のguard文以降では、年齢が18歳以上と証明されている状態になります。
正直ここまでの内容だったらif文と大差ないので好きな方を使いたくなりますが、
ここからがguard文の真骨頂になります。
##guard-let文
if文と同様にguard文もguard-let文が利用できます。
処理の流れ的にはif-let文と同じなのですが、大きな違いが一つあります。
それは、guard-let文で宣言された変数や定数は、
guard-let文以降でも利用可能という点です。
// if-let文の定数のスコープ
func makeNameIf(string: String?) {
if let name = string {
print(name + "さんこんにちは。")
} else {
print("nilです。")
}
print(name + "さんこんにちは。") // コンパイルエラー
}
//guard-let文の定数のスコープ
func makeNameGuard(string: String?) {
guard let name = string else {
print("nilです。")
return
}
print(name + "さんこんにちは。")
}
makeNameIf(string: "太郎") // コンパイルエラーで実行できない
makeNameGuard(string: "太郎")
実行結果
太郎さんこんにちは。
このようにif-let文の場合は、定数をif-let内でしか利用できないので、
if-let文の外で使いたい場合は別で変数を宣言しておく必要があります。
逆にguard-let文の場合は、guard-let文以降でも利用することができるので、
別で変数を宣言する必要がなくなります。
では、コードの違いがわかるように、
同じ機能を持ったif-let文とguard-let文を記述してみます。
どちらも、Optional<Int>型の値を2つ引数に持ち、
返り値もOptional<Int>型の返り値を持ちます。
第一引数もしくは第二引数がnilの場合は、
第一(第二)引数に値が入っていません。と表示し処理を終える流れになります。
func add(_ intA: Int?, _ intB: Int?) -> Int? {
let a: Int
let b: Int
if let wrappedIntA = intA {
a = wrappedIntA
} else {
print("第一引数に値が入っていません")
return nil
}
if let wrappedIntB = intB {
b = wrappedIntB
} else {
print("第二引数に値が入っていません")
return nil
}
return a + b
}
add(10, 10) // 20
if文の場合は、if-let文で宣言した定数はif-let文内でしか使用できないので、
定数aと定数bを別で宣言しそれに対して代入を行っています。
それに対してguard-let文は次のようになります。
func add(_ intA: Int?, _ intB: Int?) -> Int? {
guard let a = intA else {
print("第一引数に値が入っていません。")
return nil
}
guard let b = intB else {
print("第二引数に値が入っていません。")
return nil
}
return a + b
}
add(10, 10) // 20
guard文の場合は、guard-letで宣言した定数を使うことができるので
別で宣言する必要がなくなります。
このように、条件に応じて早期退出するコードの場合はguard文を使用して実装した方が、
シンプルなコードを記述することができます。
また、guard文の場合は退出処理を記述しないとコンパイルエラーになるので
単純にミスを防ぐこともできます。
if文にもguard文にも違った良さがあるので、
是非二つとも理解して使い分けれるようにしてください!
私もこの記事を書いてていろいろと発見があったのでお互い頑張りましょう!
以上、最後までご覧いただきありがとうございました。