力試し
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 は簡単ですが出題ミスではありません(話の流れ上必要だったので)。