swiftinitializerresulttypefailable

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?


Solution

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