条件式とオプショナル列挙型の併用
次のコードのように、if文の条件式にオプショナル列挙型を指定すると、中身が存在する(Some(T)である)ときに条件が成立したものとして、if文のブロックが実行されます。
var num: Int? = "1s3".toInt()
var notNum: Int! = "123".toInt()
if num {
print(num!.description())
}
if notNum {
print(notNum.description()) // !を付けずに済む
}
また、T?型とは異なり、T!型には、メソッド呼び出しで「!」を付ける必要がありません。
T!型の値がnilだった場合、元のT型に定義されたメソッドやプロパティを呼び出した時点でランタイムエラーが起こります。T?に対する!の適用と同様に、T!に対するアクセスについても、その中身がnilでないと保証されている場合に限定するのが無難でしょう。
もう1つ、例を見てみましょう。
let exist: Bool? = false
if exist {
print("exist")
} else {
print("empty")
} // exist
print("exist")とprint("empty")のどちらが実行されるか、迷う方も多いと思いますが、この場合は条件式が成立したと見なされ、print("exist")が実行されます。理由は明白で、exist変数の値はSome(false)であり、falseではないためです。if文が判定するのは、オプショナル列挙型の値の中身ではありません。
Swiftでは、条件式における挙動をLogicValueプロトコルのメソッドを通じて定義することが可能です。オプショナル列挙型はif文のみならず、while文やdo-while文、for文の条件式にも用いることができますが、それはLogicValueプロトコルに準拠しているためです。
let numStrs = ["123", "132", "1g2"]
var idx = 0
while numStrs[idx].toInt() {
println(numStrs[idx]) // 123 132
idx++
}
idx = 0
do {
println(numStrs[idx]) // 123 132
idx++
} while numStrs[idx].toInt()
for idx = 0 ; numStrs[idx].toInt() ; idx++ {
println(numStrs[idx]) // 123 132
}
toInt()で返されるInt?型が様々な条件式で使えることが分かります。
オプショナルバインディング
最後に、オプショナル列挙型とletを制御構文の条件式で併用する方法について見ていきましょう。
まず、次のコードを見てください。
var numberString: String? = "1111" // Some "1111"
if let number = numberString?.toInt() {
(number * 2).description // "2222"
} else {
println("failed")
}
if文の次の条件式で定数としてnumberを宣言していますが、こちらの構文ではnumberStirng?.toInt()というオプショナルチェーンの結果をInt?型として代入せず、結果がnilでなかった場合にだけ中身をInt型として取り出し、numberに代入します。逆に、オプショナルチェーンの結果がnilだった場合は、else以下が実行されます。
この機構はオプショナルバインディングと呼ばれ、if文のみならず、while文やdo-while文にもletを適用して、nilかどうかを確認しつつ、値を取り出すことができます。
let numStrs = ["123", "132", "1g2"]
var sum = 0
var idx = 0
while let num = numStrs[idx].toInt() {
sum += num
idx++
}
sum // 255
次回は
今回は、列挙型とオプショナル列挙型の説明を行いましたが、いかがでしたでしょうか。オプショナル列挙型に関しては、より安全に値が存在しない場合を扱えると感じていただけたのではと思います。
次回はクラスとストラクチャのプロパティ、メソッド、継承を中心に説明します。お楽しみに。
