🕊
[Swift] nil の意味を明確にする方法
モチベーション
nil を乱暴に多用していると nil が表す意味が複数に膨れ上がってしまうため、何のために nil にしているかを変数から察することができないかと考えました。
nil の意味を明確にする方法
以下のように Optional を拡張すると、変数名から nil の意味を明確にすることができます。
extension Optional {
static var nilForDefault: Wrapped? {
nil
}
static var nilForError: Wrapped? {
nil
}
}
// 使い方
var num: Int? = .nilForDefault
var str: String? = .nilForError
使い方(応用)
where Wrapped == 型名 で型を絞り込んで、nil を定義することもできます。
extension Optional where Wrapped == Int {
static var nilForXXXXX: Wrapped? {
nil
}
}
var num: Int? = .nilForDefault // nil
var str: String? = .nilForXXXXX // Type 'String' has no member 'nilForXXXXX'
そもそも
nilForError などを使うことは間違っていて、Error を throw するように実装していない証拠かもしれません。
以上です。
補足(ダメな例)
ダメな例 その1
以下ではうまくいきません。
enum Nil {
static let forDefault: Optional<Any> = nil
}
var num: Int? = Nil.forDefault as! Int // expression failed to parse: error: op.playground:3:5: error: consecutive statements on a line must be separated by ';'
そもそも Nil.forDefault は Optional<Any> 型であり、Optional<Int> ではないので、as! or as? で型を判定しなければならなく、うまくいきません。
ダメな例 その2
Optional<Any> でダメなら、型を指定すればよいという考え方です。
struct Nil {
static let forDefault: Optional<Int> = nil
}
var num: Int? = Nil.forDefault // OK
var str: String? = Nil.forDefault // NG: Cannot convert value of type 'Optional<Int>' to specified type 'String?'
as! or as? でキャストする必要はなくなりましたが、すべての型において、いちいち定義しなければならないので、使い勝手が悪いです。
ダメな例 その3
static で生やさない場合の例になります。
extension Optional {
var nilForDefault: Wrapped? {
nil
}
}
var num: Int? = .nilForDefault // ← これはできない
// これならできるが、やりたいことではない
num = 0
num.nilForDefault // nil
一度インスタンスを生成しないと、使えません。
用途が異なります。
以上、補足でした。
Discussion