I was exploring if-case-let
statements that work with Result
type and do not want to use switch-case for this
Consider the following code:
import Foundation
enum CustomError: Error {
case missingData
}
func somethingThatMightReturnError() -> Result<Data,CustomError> {
.failure(.missingData)
}
func compute() -> Result<String,CustomError> {
let computedValue = somethingThatMightReturnError()
guard case Result.success(let data) = computedValue else {
/// How to return the CustomError that is inside the computedValue ???
}
/// Here goes a lot of complex and long code that converts the Data returned as success into String which we need to return
// I have force-unwrap and converted to get rid of the error
return .success(String(data: data, encoding: .utf8)!)
}
How do I access the .failure(error)
inside the guard’s else statement and return that error
parameter (of .failure) from the function? Is it possible or switch-case is the only thing that works here?
2
Answers
If
computedValue
is notsuccess
then it’sfailure
so simply doIf you need to map to different success type the you can just add a dummy
map
inside at theguard
But in this case I would consider a completely different approach that changes the function to be throwing instead
Instead of restricting your approach arbitrarily to use
guard
, I think it is better to use the patterns that Result actually provides. I am very fond of the magicalget
, which turns a Result into a success returned value or a thrown error. One simple approach for your use case, if we adoptget
, is to return an Error instead of a CustomError, and let the caller deal with it:In that formulation, we do fail with the error that was thrown, but we don’t worry about its type, and we don’t need to "look inside" the incoming Result; we just "rethrow" it into the returned Result failure. You have to admit that that is beautifully compact and clear, and we didn’t use
switch
(and we didn’t usecase let
either).If you really really insist on returning a Result whose Error is restricted to being a CustomError, you can just bow out (not gracefully) if the incoming Error turns out not to be a CustomError:
Having said all of that, I would recommend that if at all possible you should abandon Result completely. It is pretty much completely replaced by Combine, and then by
async/await
. It isn’t 100% dead, but you are arguably spending your ingenuity in the wrong place. 🙂