👀

`Result {}`という初期化が見慣れなかったので紹介

2024/05/06に公開

はじめに

iOSエンジニアをしている、Nao-RandD です 🚴🏻‍♂️

Swiftを実装する中で、Resultを利用することは多いかと思いますが、Result {}のようなクロージャーを用いた初期化がされている時にピンとこなかったため、その備忘録も兼ねた記事になります。

以下のようにして、Resultをクロージャーで初期化することができます。(雑なサンプルでごめんなさい 🙉)

func hoge(isSuccess: Bool) -> Result<String, MySomeError> {
    Result {
        if isSuccess {
            return "Success"
        } else {
            throw MySomeError.receiveNotSuccess
        }
    }
}

"こんな書き方できたのか"、となったのでここから紹介していきます。

Result型とは?

特に説明するまでもないかも知れませんので、”知っているよー”という方は読み飛ばしてください 🤗

Resultは、Swift 5.0 で導入された、成功または失敗のいずれかを表すことのできる型になります。

成功、失敗をそれぞれassociated valueとして独自に定義することができます。

  • success(T): 処理が成功した場合の結果を保持します。
  • failure(Error): 処理が失敗した場合のエラーを保持します。

成功した場合にはIntで、失敗した時にはMyValueErrorとしてResultを定義するならResult<Int, MyValueError>のような感じですね。

https://developer.apple.com/documentation/swift/result

今回のクロージャーを用いた初期化

それでは、クロージャーを用いたResultを扱う方法に進んでいきましょう。

クロージャーでの初期化は、catchingという() throws -> Successのクロージャーを渡しています。

https://developer.apple.com/documentation/swift/result/init(catching:)

簡単な例が良いかと思いますので、引数でnumerator(分子)とdenominator(分母)を受け取り、除算を行うメソッドを例に考えてみましょう。

クロージャーを用いない場合には以下のようなコードになるかと思います。

enum MathError: Error {
    case divisionByZero
}

func divide(_ numerator: Int, by denominator: Int) -> Result<Int, MathError> {
    if denominator == 0 {
        // 0除算は許容しないためMathError.divisionByZeroを返す
        return .failure(MathError.divisionByZero)
    }
    return .success(numerator / denominator)
}

// 使用例
let result = divide(10, by: 2)
switch result {
case .success(let quotient):
    print("Result: \(quotient)")  // 分母が2の場合、出力は "Result: 5"
case .failure(let error):
    print("Error: \(error)")
}

これをクロージャーでのResult初期化を利用して以下のように書くことができます。

func divide(_ numerator: Int, by denominator: Int) -> Result<Int, MathError> {
    Result {
        if denominator == 0 {
            throw MathError.divisionByZero
        }
        return numerator / denominator
    }
}

// 使用例
// ・・・(上と同じ)

Resultのクロージャーでの初期化を利用すると、

  • 成功:.successのassociated valueでreturn
  • 失敗:.failureのassociated valueでthrow
    で表現することができます。

成功時にはreturnし、失敗時にはthrowして、通常のthrowsメソッドのように記述することができるわけですね。

まとめ

”使わないと損”というものではないと思いますが、.success, .failureで書かずに、return, throwで扱えるため実装時にはこちらの方が使いやすいなと思ったりしました🤔

今回はResultのクロージャーでの初期化に出会って、”ナニコレ👀”となったので自身の備忘録がてら記事にさせていただきました。

Discussion