力試し
Optional は Swift を使う上でとても重要です。 Optional を使いこなせているか試してみて下さい。
Optional を使って次のことをやる場合に、 簡潔かつ安全 に書く方法を考えて下さい。
-
a: Int?があるとき、aの値を二乗したい。ただし、aがnilの場合はnilを得たい。 -
array: [Int]?があるとき、arrayの最初の要素を取得したい。ただし、arrayがnilか、最初の要素が存在しない(Arrayが空の)場合はnilを得たい。(ヒント:[Int]はfirst: Int?というプロパティを持つ。firstは最初の要素が存在しない場合はnilを返す。) -
x: Double?があるとき、xの平方根を計算したい。ただし、xがnilまたは負の数の場合はnilを得たい。なお、sqrtを安全にした(負の数を渡すとnilを返す)関数safeSqrt: Double -> Double?があるものとして考えて良い。 -
a: Int?とb: Int?があるとき、a + bを計算したい。ただし、aかbがnilの場合にはnilを得たい。 -
a: Int?があるとき、aの値をprintで表示したい。ただし、aがnilの場合には何も表示したくない。
1, 2, 4 では結果の型が( Int ではなく) Int? に、 3 では Double? になることに注意して下さい。また、 3 の safeSqrt は次のように実装できます。
func safeSqrt(x: Double) -> Double? {
return x < 0.0 ? nil : sqrt(x)
}
ダメな解答例
簡潔でない例
下記はいずれも正しい結果が得られますが 簡潔ではありません。
1.
let result: Int?
if let a0 = a {
result = a0 * a0
} else {
result = nil
}
たかが値を二乗するためだけに Optional binding で分岐して計算するなんてやってられません。
2.
let result: Int?
if let array0 = array {
result = array0.first
} else {
result = nil
}
3.
let result: Double?
if let x0 = x {
result = safeSqrt(x0)
} else {
result = nil
}
4.
let result: Int?
if let a0 = a, b0 = b {
result = a + b
} else {
result = nil
}
5.
if let a0 = a {
print(a0)
}
安全でない例
下記はいずれも正しい結果が得られますが 安全ではありません。また、一見短くて簡潔なように見えますが、 nil チェックと三項演算子、 Forced unwrapping ( ! )の組み合わせは複雑で、簡潔とは言えません。
1.
let result: Int? = a == nil ? nil : a! * a!
せっかく Optional によって安全なコードが書けるようになっているのに、 ! を使ったら台無しです。 nil チェックをしていても : の左右を書き間違えるなどしたら Forced unwrapping に失敗してクラッシュしてしまいます。コードを読む人も ! を見かける度に、この ! はいつも安全なのか、それとも異常系ではクラッシュしてしまうのかを考えなければなりません。
また、わざわざ nil チェックをしなければならないなんて Optional がない時代まで逆戻りしており、 Optional の恩恵を享受できていません。まるで Java で書いているみたいです。
// Java
Integer result = a == null ? null : a * a
2.
let result: Int? = array == nil ? nil : array!.first
3.
let result: Double? = x == nil ? nil : safeSqrt(x!)
4.
let result: Int? = a == nil ? nil : b == nil ? nil : a! + b!
模範解答は・・・
"SwiftのOptional型を極める" で解説しています。この力試しもその一部だったんですが、長くなりすぎたので分離しました。
なお、 2 は簡単ですが出題ミスではありません(話の流れ上必要だったので)。