I have a struct MyStruct
. It can be initialized from a String, but there are many ways for the String to be invalid. Rather than simply creating a failable initializer init?(string: String)
which returns the same nil
in all of the failure cases, I would like to have an initializer that returns a Result type of Result<MyStruct, Error>
so that the calling method can know which failure case occurred and report an informative error.
I can write a method static func makeNew(string: String) -> Result<Self, Error>
. That way instead of calling
guard let new = MyStruct(string: someString) else {
print("\(someString) was invalid somehow.")
}
print("Object created.)
I could call makeNew
like this:
switch MyStruct.makeNew(string: someString) {
case .success(let new):
print("Object created")
case .failure(let error):
switch error {
// handle each specific error appropriately
}
}
Is this the only way, or does Swift give us an actual initializer to do this?
You can throw
from your initializer instead:
struct MyStruct {
struct ValidationError: Error {} // Example error
init(_ string: String) throws {
guard isValid() else { throw ValidationError() }
...
}
}
do {
let new = try MyStruct("some string")
print("Object created: \(new)")
} catch let e as MyStruct.ValidationError {
// handle each specific error appropriately
} catch {
print("Other unexpected error")
}
Functions that return T
(or initializers for T
) marked throws
are roughly isomorphic to ones that return Result<T, any Error>
.