Swiftに慣れてくると!を避けたくなりますが、!を書きたくなるようなケースもあります。

func someFunc(handler: (String?, NSError?) -> Void)
someFunc { string, error in
    if error != nil {

    } else {
        // ここで!を使いたくなる
    }
}

Resultを使って以下のように書き直すと!を避けられます。

func someFunc(handler: Result<String, NSError>) -> Void)
someFunc { result in
    switch result {
        case .Success(let box): // box.value: String
        case .Failure(let box): // box.value: NSError
    }
}

また、元のコードのvalue, errorは両方ともOptionalなので、以下の4つの組み合わせが存在します。

  • None, None
  • None, Some
  • Some, None
  • Some, Some

元のコードは(None, None)と(Some, Some)を考慮していません。 つまり、実行時には(None, Some)と(Some, None)の2パターンしか存在しないという約束を前提としたコードとなっています。 Resultを利用するとそのような約束を型で表すことができ、2パターンしか存在しないことがコンパイル時に保証されるようになります。

Cocoaの伝統的なメソッドに対してもResultを使用できます。

var error: NSError?
let object = NSJSONSerialization.dataWithJSONObject(object, options: options, error: &error)
let result = try { error in
    NSJSONSerialization.dataWithJSONObject(object, options: options, error: error)
}

map, flatMapもあるので連続した処理もシンプルに書けます。

let connectionResult = try { error in
    NSURLConnection.sendSynchronousRequest(request, returningResponse: response, error: error)
}

let parseResult = connectionResult.flatMap { data in
    try { error in
        NSJSONSerialization.JSONObjectWithData(data, options: options, error: error)
    }
}

 

APIKitでもantitypical/Resultを活用しています。