我有一个Swift Result
数组,像这样:
let tuple: [Result<Term, TermError>] = /* code here */
我想将其内翻,将结果拉出以给出单个结果,并将数组推入其中。
let tuple2: Result<[Term], TermError> = /* How? */
如果tuple2
的任何为.failure
,则 tuple
应该为.failure
。否则为.success([tuple-elements-in-here])
。
我想我可以提出一些可以使这项工作奏效的方法,但是我觉得应该有一种相当干净的方法来实现这一目标?
答案 0 :(得分:5)
您实际上只是在尝试为sequence
monad在Swift中为Haskell Monads重新创建Result
函数。我们可以像Haskell implemented it一样完全实现它。
sequence :: Monad m => [m a] -> m [a]
sequence = foldr mcons (return [])
where mcons p q = p >>= \x -> q >>= \y -> return (x:y)
在Swift中,这看起来像:
func sequence<T, E: Error>(_ arrayOfResults: [Result<T, E>]) -> Result<[T], E> {
return arrayOfResults.reduce(.success([])) { (p, q) in
return p.flatMap { x in return q.map { y in return x + [y] } }
}
}
用法:
let tuple2 = sequence(tuple)
答案 1 :(得分:2)
您可以在Array
上定义一个Array<Result<Value,Error>> to
来转换extension Array {
func flatMapResult<Value, Error>() -> Result<Array<Value>,Error> where Element == Result<Value,Error> {
let valuesAndErrors = self.map { element -> (value: Value?, error: Error?) in
switch element {
case .failure(let error):
return (nil, error)
case .success(let value):
return (value, nil)
}
}
if let firstElementWithError = valuesAndErrors.first(where: {$0.error != nil}), let firstError = firstElementWithError.error {
return .failure(firstError)
} else {
let values = valuesAndErrors.compactMap { $0.value }
return .success(values)
}
}
}
Result,Error>`,如下所示。
enum MyError: Error {
case err
}
let arrayOfResults: Array<Result<Int,MyError>> = [.success(8), .success(2), .success(3)] // success([8, 2, 3])
let arrayOfResultsWithFailure = arrayOfResults + [.failure(.err)] // failure(__lldb_expr_2.MyError.err)
arrayOfResults.flatMapResult()
arrayOfResultsWithFailure.flatMapResult()
使用代码示例:
export class FilterType {
constructor(
public priority: number,
public name: string) {
}
}
答案 2 :(得分:1)
您可以使用map
函数并在失败的情况下引发错误。
类似这样的东西:
let tuple2: Result<Array<Term>, TermError>
do {
let result = try tuple.map { result -> Term in
switch result {
case .failure(let error):
throw error
case .success(let value):
return value
}
}
tuple2 = .success(result)
} catch let error as TermError {
tuple2 = .failure(error)
} catch { fatalError("Unknown error") }
print(tuple2)
您可以将其移入扩展程序以重用。