Swift; init! と init? の使い分け

最近Swiftのコーディングを始めている。

Appleのドキュメントでは「失敗することのあるinitializerはinit!かinit?なんだ」というざっくりとした説明があるのだが、それらを具体的にどう使い分けるのかちゃんとした記載がなく、検索しても意外と触れている人間が見つからなかった。ということで個人メモ。ちゃんと調べてないので、オレオレ && 二番煎じの可能性あり。

前提としてOptionalの話。Optionalについては http://qiita.com/cotrpepe/items/518c4476ca957a42f5f1 にまとまっているが、要はSwiftでは通常の型の範囲に無効値であるnilを含むことが許されないため、無効値がありうる場合は[普通の型 または nil ]という派生型にパックして扱うという話である。つまり関数型でいうところのMaybeにあたる。

で、これらは基本的に変数に対する修飾として機能するのだが、nilを生み出す源として、インスタンス生成の失敗というものがでてくる。例えば存在しないファイルパスからNSDataをつくろうとすれば、当然インスタンスはnilを返さざるをえない。このような失敗するイニシャライザは!また?によって自分がパラメータによって失敗しうることを示す必要がある。問題はinit!とinit?はどう違うかということである。

上記のリンクで整理されていることを設計思想的に解釈すると、!はnullptr方式で「nilが入っていてもいいが、nilの時に使ってはいけない」ということであり、一方?はobjc由来のnilにメッセージを送る方式で「nilに対して何をしてもnilである」ことを示していると思われる。

例えばこんなクラスを考えてみる。

class Test {
    init!(f:Bool)
    {
        if !f {
            return nil
        }
    }
    
    init?(g: Bool)
    {
        if !g {
            return nil
        }
    }

    func show()
    {
        println("bow!")
    }
}

パラメタfの方のイニシャライザは!指定であるから、アンラップは暗黙で行われる。「ヌルポで呼ぶなよ?」というやつで、そのため

let t = Test(f: false)
f.show() // runtime error

というのは文法的には合法だが、実行時エラーを発生する。もしこれを回避したければif let受けするのがSwift的にはスタンダードなんじゃないかと思う。

if let t = Test(f: false) {
    t.show()
}
else
{
    // tがnilの時の処理
}

一方パラメタgの時のイニシャライザは?指定なので、アンラップはプログラマの仕事である。よって

let t2 = Test(g: false)
t2.show()

というコードはそもそも文法的に許されず、

t2!.show() // runtime error
t2?.show() // nil

のどちらかを書くことになる。

コーディングの見た目としては、おそらく明示的にアンラップしなければ使えない後者の方が安全なので、init!をどうしても使わなくてはならない理由はどうも思い当たらない。なにせinit!にしたところで、

let t = Test(f: false)
t?.show() // nil

と明示的に?で外せばinit?と同じことになるし、逆にinit?にしてもif letで受けた場合は!/?を省略できる点を考慮すると、生成失敗のnilチェックを厳密にする手間は同じであるように思える。

ちなみにプロパティについては、!/?の適材適所がそれぞれあると見た。
?修飾のプロパティは、objcでよくあるnil許容の値に使うべきで、nilチェインを認めないなら使わないほうが無難だろう。

!修飾は、個人的にはhas-aで補助インスンタンスを持つタイプのクラスが、init!/?で変数初期化を保証するために使うといいのではないかと思う。

というのは、init中で必須の補助インスタンス生成が失敗したらさっさとnilを戻して脱出して欲しいのだが、Swiftの文法はインスタンス変数未初期化のままでinitのnil脱出を認めないということになっている。そのため、とりあえずnilで初期化しておいて、実際はnilのままでは使えない!修飾にしておけば、「他のメソッドは変数は正しく設定されている前提で動きますからね!」というような主張になる。まあ、多分に好みの問題ではあるのだが・・・。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です