配列の要素をオプショナルバインディング

はじめに

コードレビューで、ちょっと不思議なコードがあったのでメモ。

結論

配列の添字アクセスをオプショナルバインディングしてもビルドエラーにならないけど、わかりにくいのでやめたほうがいい。

コード

var hoge:[Int] = []

// hogeを更新する処理など

if let n: Int = hoge[0] { //ランタイムエラー
    print(n)
}
else {
    print("nothing")
}

一見すると良さそうですが、配列が空っぽなのでコメントした行で fatal error: Index out of range になります。

当たり前といえば当たり前ですね。

改善案

配列でこういった判定を行うなら、空配列の判定したほうがわかりやすい気がします。

if hoge.isEmpty {
    print("nothing")
}
else {
    print(hoge[0])
}

そもそも、配列アクセスでnilが返る可能性を想定したコードになっていますが、hogeInt型の配列であって、Optional<Int>型の配列ではないので、オプショナルバインディングは適切ではないです。

なんでビルドエラーにならないのかは謎です。

どうしてもオプショナルバインディングしたい場合

if let n: Int = hoge.first {
    print(n)
}
else {
    print("nothing")
}

今回の場合は、配列の最初の要素にアクセスしたいので、Array クラスの first プロパティでOK。

first はオプショナル型なので問題なし。

似たようなプロパティとして最後の要素を参照する last もあります。

どちらも正確には Array クラスに適用している CollectionType プロトコルの特徴ですが。