Resultについて

2021年03月09日

APIにアクセスし結果を返すような Errorも合わせて返すような場合に使用 します


Result型は以下のように定義されています

public enum Result<Success, Failure> where Failure : Error {
    case success(Success)
    case failure(Failure)
}




例えば、アプリ起動時にAPIにアクセスしたと仮定し、 データの取得に成功/失敗した場合で返す値を分けるのを Result を使って書くと以下のようになります

/// 返す結果のモデル
struct User {
    let id: Int
    let name: String
}

/// Errorに準拠したenumを定義する必要がある
enum AppError: Error {
    case networkError
    case calcError
}

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
    // アプリ起動時によばれるメソッド
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

        loadUser(canLoadData: false, handler: { result in
            switch result {
            case .success(let user):
                print(user)
                // => canLoadDataがtrueの場合、 User(id: 1, name: "taro")
            case .failure(let error):
                print(error)
                // => canLoadDataがfalseの場合、 networkError
            }
        })

        return true
    }

    /// canLoadDataがtrueの場合成功を想定した値を、falseで失敗を想定した場合の値を返す
    private func loadUser(canLoadData: Bool, handler: (Result<User, AppError>) -> Void ) {
        let user = User(id: 1, name: "taro")
        // APIにアクセスしたと仮定し、データの取得成功/失敗の結果で返す値を変える
        canLoadData ? handler(.success(user)) : handler(.failure(AppError.networkError))
    }
}

使用方法

使用する時以下2つを意識します

  • Succes には 結果として返したい型 を定義
  • Failure には Errorに準拠したenum を用意

Result型を定義する

1. Errorに準拠した型を用意

まず Error に準拠した型を用意します

enum AppError: Error {
    case networkError
    case calcError
}

2. ResultでSuccessを使う

Success で文字列型を返すResult型を使う場合

func loadResult() -> Result<String, AppError> {
    return Result<String, AppError>.success("hello world!")
}

省略して書くことも出来ます

func loadResult() -> Result<String, AppError> {
    return .success("hello world!")
}

3. ResultでFailureを使う

Failure でAppError型を返すResult型を使う場合

func loadResult() -> Result<String, AppError> {
    return Result<String, AppError>.failure(AppError.networkError)
}

省略して書くことも出来ます

func loadResult() -> Result<String, AppError> {
    return .failure(.networkError)
}

例えば isSuccess というフラグに応じて成功/失敗の別のResult型を返す場合以下のようになります

func loadResult(isSuccess: Bool) -> Result<String, AppError> {
    // isSuccessに応じて成功/失敗のResultを返す
    return isSuccess ? .success("hello world!") : .failure(.networkError)
}

Result型を使う

以下のように関数を定義した場合、

func loadResult(isSuccess: Bool) -> Result<String, AppError> {
    // isSuccessに応じて成功/失敗のResultを返す
    return isSuccess ? .success("hello world!") : .failure(.networkError)
}

使用する側では以下のように使います

let result: Result<String, AppError> = loadResult(isSuccess: true)

switch result {
case .success(let str):
    print(str)
    // => "hello world!"
case .failure(let error):
    print(error)
    // => networkError
}

おすすめ