Let\'s assume an array of Result
. We want the array to be reduced to a Result
of an array. For example:
let z: [Result
You can create a generic method and remove the constraint from the extension:
extension Sequence {
func reduced<T>() -> Result<[T], Error> where Element == Result<T, Error> {
reduce(.success([])) {
switch $0 {
case .failure: return $0
case let .success(array):
switch $1 {
case let .failure(error): return .failure(error)
case let .success(value): return .success(array + CollectionOfOne(value))
}
}
}
}
}
Btw you can also use a plain loop and provide an early exit at the first failure:
extension Sequence {
func reduced<T>() -> Result<[T], Error> where Element == Result<T, Error> {
var array: [T] = []
for result in self {
switch result {
case let .failure(error): return .failure(error)
case let .success(value): array.append(value)
}
}
return .success(array)
}
}
A more concise approach would be to create a generic method that throws or return an array with all successes:
extension Sequence {
func successes<T, E>() throws -> [T] where Element == Result<T, E>, E: Error {
try map { try $0.get() }
}
}
Playground testing:
let z: [Result<Int, MyError>] = [.success(1),
.success(2),
.success(3)] //,
//.failure(.blah)]
do {
let successes = try z.successes()
print(successes) // [1, 2, 3]
} catch {
print(error)
}
You can move constraints to the function to make it generic:
extension Array {
func reduced<T>() -> Result<[T], Error> where Element == Result<T, Error> {
return self.reduce(.success([T]())) { accumulator, result in
...
}
}
}
Note: A variable of type Int
will not match Any
as it's a different type. Variables of type Any
need to be casted down to Int
.