Anton
Anton

Reputation: 3277

Failable initializer with Result type?

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?

Upvotes: 1

Views: 75

Answers (1)

Alexander
Alexander

Reputation: 63321

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>.

Upvotes: 5

Related Questions