はじめに
非常に便利なEnumのAssociatedValueですが、定義を変更する際には注意が必要です。
誰かが同じ過ちを繰り返さないよう、私が実際に起こしたデグレを紹介します。
変更前
例えば、以下のようなEnumがあったとします。
enum Hoge {
case foo(value: Int)
case bar(value: Int)
}
このEnumを、こんな感じで使っていたとすると、
let hoge = Hoge.bar(value: 10)
if case .bar(let value) = hoge {
self.label.text = "Value = \(value)"
}
変更後
ここで、barに対して何かしらの定義を追加したくなりました。
enum Hoge {
case foo(value: Int)
case bar(value: Int, value2: Int)
}
定義が追加されたことで、変数hoge
を定義している箇所では、Missing argument for parameter 'value2' in call
というコンパイルエラーが発生する為、以下のように変更を行います。
let hoge = Hoge.bar(value: 10, value2: 20)
しかし、実際にhoge
が使われている箇所では、コンパイルエラーは発生しません。
Enumの変更前に記述したまま(以下の内容)でも何も怒られないのです。
if case .bar(let value) = hoge {
self.label.text = "Value = \(value)"
}
実際に上記の状態で動かしてみると、画面には以下のように表示されます。
そうです。
case .bar(let value)
のvalue
には、(value: Int, value2: Int)
のタプルが代入されてしまったのです。
まとめ
EnumのAssociatedValueの定義を変更した場合、それを使っている箇所ではエラーにならない為、注意が必要という内容でした。
※定義を減らす場合には、使っている箇所でもエラーになります。
例えば、bar(value: Int, value2: Int)
からbar(value: Int)
へ変更した場合、Tuple pattern has the wrong length for tuple type '(value: Int)'
というエラーになります。
この件は『プログラムの修正を行う場合は、影響範囲を調査し、全ての箇所で動作を確認する。』という基本を改めて思い出させてくれる出来事でした。