Swift Result型入門|成功/失敗を明示する実装パターンを初心者向けに徹底解説
生徒
「先生、SwiftでResult型っていうのを見たんですけど、これは何をするものなんですか?」
先生
「Result型は、処理が成功したか失敗したかをはっきりと表現するための仕組みなんです。成功なら結果の値、失敗ならエラーを持たせることができます。」
生徒
「じゃあ、普通にエラーを投げるのとどう違うんですか?」
先生
「エラーを投げる方法もありますが、Result型を使うと成功と失敗の両方をひとつの型で扱えるので、コードが分かりやすくなるんです。実際に使い方を見ていきましょう!」
1. SwiftのResult型とは?
SwiftのResult型は、処理の結果が「成功」か「失敗」かを安全に表現するための型です。成功したときには値を持ち、失敗したときにはエラーを持つことができます。つまり「成功か失敗か」という二択をはっきりとコードで表現できるのが特徴です。
Result型は以下のように定義されています。
enum Result<Success, Failure: Error> {
case success(Success)
case failure(Failure)
}
ここでSuccessは成功時の値の型、Failureは失敗時のエラーの型を表します。これにより、関数の返り値に「成功か失敗か」をまとめて返せるようになります。
2. Result型の基本的な使い方
例えば「文字列を数字に変換する」処理を考えてみましょう。成功すれば数値を返し、失敗すればエラーを返すようにResult型を使います。
enum ParseError: Error {
case invalidFormat
}
func stringToInt(_ str: String) -> Result<Int, ParseError> {
if let number = Int(str) {
return .success(number)
} else {
return .failure(.invalidFormat)
}
}
このように書くことで、「成功か失敗か」をひとつの返り値で明示できます。
3. Result型の値を取り出す方法
Result型を使ったあとは、switch文を使って「成功か失敗か」を分けて処理するのが基本です。
let result = stringToInt("123")
switch result {
case .success(let value):
print("変換成功: \(value)")
case .failure(let error):
print("変換失敗: \(error)")
}
実行すると、次のように出力されます。
変換成功: 123
このようにResult型を使えば、成功と失敗を見やすく分けて書けます。
4. Result型とdo-catchの違い
Swiftにはthrowとdo-catchを使ったエラーハンドリングもあります。しかし、throwは処理が途中で中断されるため、呼び出し側での扱いが少し複雑になります。
一方、Result型は返り値として「成功か失敗か」を受け取れるので、非同期処理や複数の処理を組み合わせる場面で特に便利です。たとえばネットワーク通信の結果を扱うときによく使われます。
5. mapとflatMapでResultを変換する
Result型は「成功の値」に対して変換を行う便利なメソッドを持っています。mapを使えば、成功した場合だけ値を変換できます。
let result = stringToInt("10")
let doubled = result.map { $0 * 2 }
switch doubled {
case .success(let value):
print("2倍にした結果: \(value)")
case .failure(let error):
print("エラー: \(error)")
}
この例では、成功したときにだけ値を2倍に変換しています。失敗した場合はそのままエラーが伝わります。
6. 非同期処理でのResult活用
現実的な開発では、サーバーからデータを取ってくる「非同期処理」でよくResult型が使われます。非同期処理とは、すぐに結果が返らず、時間がかかる処理のことです。
func fetchData(completion: (Result<String, Error>) -> Void) {
let success = true
if success {
completion(.success("データ取得成功"))
} else {
completion(.failure(NSError(domain: "Network", code: -1)))
}
}
fetchData { result in
switch result {
case .success(let data):
print(data)
case .failure(let error):
print("エラー: \(error)")
}
}
このように、非同期処理の結果をResult型で受け取れば、成功と失敗を明示的に分けて書けるので安心です。
7. 初心者が覚えておくべきResult型のポイント
- Result型は「成功」か「失敗」を表すための型
- 成功なら値を、失敗ならエラーを持たせる
- switch文で分けて処理できる
- mapやflatMapで変換も可能
- 非同期処理で特に便利に使える
これらを理解しておくと、Swiftでのエラーハンドリングが一気に分かりやすくなります。