Optional型
Optional型はSwift入門者には結構ハマる点のようで、Qiitaにもよく記事が上がっているのを見かけます。
もちろんかなり趣味も大いにあると思うけれど、「空にできるのがOptional!」などという表現には、本質的でないと感じます。あくまで、nilは「空である」ことを意味する値だと思っています。
先日こんなツイートがありました。とても的を射ていて、わかりやすいと思います。
0とnullの違い pic.twitter.com/MbZQEVXWSX
— こーすけ (@travelgray) 2017年11月7日
ただし、Swiftでは少し違うと思っていて、
Swiftでのnullは、本当に何もない、看板すらない状態だと思います。
そしてこの看板がOptionalであり、数字または nil
がセットされます。
以降シチュエーションはすこし極端目に書きますが、もちろん似ていてもそうじゃないときも往々にしてあると思うので、ご容赦ください。
Optionalはめんどくさい
そもそも、Optionalは面倒くさい。
Optionalを画面に反映したり、サーバーに送ったりするには、必ずUnwrapしなければいけないので、直接の値のほうが嬉しい。
もちろん、Optionalが必要なシーンも多くありますし、自分もかなりの頻度で使います。
例:Bool?
型
例えば、Bool?
型の値の意味ってなんだろう?
let isValid: Bool?
さて、このコードで isValid
が nil
だった時、その状態は果たしてvalidなのかinvalidなのか?
nilの意味
Optionalはnilまたは値を入れられる型だと考えます。
nilは何かしらの意味を持つべきで、意味が無いならOptionalを使うべきではない。
例えば、サーバーからのレスポンスは、届くまでに時間がかかる。この時に Bool?
型を使うのであれば、以下のようにみなせます。
値 | 意味 |
---|---|
nil | 通信前、通信中 |
true | 通信の結果、true |
false | 通信の結果、false |
値を入力してもらう画面の場合、
値 | 意味 |
---|---|
nil | 未入力 |
true | 入力の結果、true |
false | 入力の結果、false |
もちろん、Bool以外についても同じことが言えるし、こういうOptionalは積極的に使うべきだと思います。
ただ、例えばオブジェクトがvalidかどうかはどんな状態かによらず分かりたいし、 _isValid = nil
がvalidかinvalidかはビジネスロジック依存だと思うので、getterなどで、外部へのインターフェースは非オプショナルのほうが良い場合も多いと思います。
これで、意味がより明確になります。
private var _isValid: Bool?
var isValid: Bool {
return _isValid ?? false
}
デフォルト引数としてのnil?
init(color: UIColor? = nil) {
if let color = color {
self.color = color
} else {
self.color = .white
}
}
引数がないことを表すnilです。が、これは本当に意味があるのでしょうか?
個人的にはプログラムの中で「引数がない」という情報はさほどどうでもよく、挙動の中で「どんな色であるか」という情報だけが大事だと考えます。
よって、以下のように書く方を好みます。
init(color: UIColor = .white) {
self.color = color
}
??
演算子と同じで、「デフォルト値である」ことがわかりやすくて良い気がしています。
??
演算子
??
演算子はアンラップを行うというより、Optiona -> 非Optionalへの変換だと感じています。
optionalValue ?? defaultValue
nilの時のデフォルト値を右辺に設定することで、非Optionalとみなせます。
エラーの時にnil?
関数の返り値で、「エラーの時にnilになります」という運用はどうでしょうか。自分は、throwsのほうが良い場合が多いと思います。
まず、throwableなメソッドの呼び出し時に、Optionalに変換することは簡単です。
// エラーを無視してOptionalに変換する、エラー時はnil
let a = try? throwable()
更に、nilだけだとエラーの内容はわかりませんが、throwすればcatchして中身を見ることができます。
もちろん実装コストはかかるので、エラーが明らかなときや何でも良い時、忙しいときは、Optionalでよいです。
でも結局あなたの趣味なんでしょ?
もちろん、その通りです。
例えばUILabelのtextはOptional型ですが、自分が実装するならOptionalにしないし、あまり何故かわかっていないです。
でも、自分は例えば登録後にサーバーに保存するユーザー名を ""
でなくて nil
にする必要はないと思うし、 ""
にしてから保存します。
議論するの好きなので、どしどしお待ちしています!