Result<Success, Failure>
| Since: | Swift 5.0(2019) |
|---|
Swift's Result type is an enum that represents either success (.success) or failure (.failure). Use it when you want to treat errors as values in asynchronous operations or function return types.
Syntax
// Result type definition
// Result<Success, Failure> (Failure must conform to the Error protocol)
let result: Result<String, Error> = .success("data")
let error: Result<String, Error> = .failure(SomeError.failed)
// Pattern matching with switch
switch result {
case .success(let value):
print("Success: \(value)")
case .failure(let error):
print("Failure: \(error)")
}
// Convert to throws using get()
let value = try result.get()
Method List
| Method | Description |
|---|---|
| get() | Returns the success value. Throws an error if the result is a failure. |
| map(_:) | Transforms the success value and returns a new Result. |
| mapError(_:) | Transforms the failure error and returns a new Result. |
| flatMap(_:) | Applies a closure that uses the success value to return another Result. |
| flatMapError(_:) | Applies a closure that uses the failure error to return another Result. |
Sample Code
sample_result_type.swift
enum AppError: Error {
case notFound
case parseError(String)
}
// Function that returns a Result
func fetchUser(id: Int) -> Result<String, AppError> {
let users = [1: "user_1", 2: "user_2", 3: "user_3"]
if let user = users[id] {
return .success(user)
} else {
return .failure(.notFound)
}
}
// Pattern matching with switch
let result = fetchUser(id: 2)
switch result {
case .success(let name):
print("User: \(name)")
case .failure(let error):
print("Error: \(error)")
}
// map: transform the success value
let upperResult = result.map { $0.uppercased() }
print("Uppercase: \(try! upperResult.get())")
// flatMap: use the success value to create another Result
func fetchDetail(name: String) -> Result<String, AppError> {
return .success("\(name)'s profile")
}
let detail = result.flatMap { fetchDetail(name: $0) }
print(try! detail.get())
// Convert to throws using get()
do {
let name = try fetchUser(id: 99).get()
print(name)
} catch AppError.notFound {
print("User not found")
} catch {
print("Error: \(error)")
}
// Using with callback-based APIs
func loadData(completion: (Result<[String], Error>) -> Void) {
completion(.success(["item1", "item2", "item3"]))
}
loadData { result in
switch result {
case .success(let items): print("Fetched: \(items)")
case .failure(let error): print("Failure: \(error)")
}
}
Running the above produces the following output:
swift result_type.swift User: user_2 Uppercase: USER_2 user_2's profile User not found Fetched: ["item1", "item2", "item3"]
Notes
The Result type treats errors as values, making it well-suited for asynchronous callbacks and function chaining. Both the success and failure cases can be expressed in a single return value.
Using map and flatMap, you can build a pipeline that transforms success values without explicit error checks at each step. In environments where Swift Concurrency (async/await) is available, using async throws functions instead of callbacks results in more readable code.
For defining errors, see Error / Defining Errors with enum.
If you find any errors or copyright issues, please contact us.