结果与提高F#异步? [英] Result vs raise in F# async?
问题描述
在async
工作流程中似乎有两种方法可以返回错误:raise
和Result
.
It seems like there are two ways to return errors in an async
workflow: raise
and Result
.
let willFailRaise = async {
return raise <| new Exception("oh no!")
}
let willFailResult = async {
return Result.Error "oh no!"
}
对于呼叫者,处理方式略有不同:
For the caller, the handling is a bit different:
async {
try
let! x = willFailRaise
// ...
with error ->
System.Console.WriteLine(error)
}
async {
let! maybeX = willFailResult
match maybeX with
| Result.Ok x ->
// ...
| Result.Error error ->
System.Console.WriteLine(error)
}
我的问题是:
- 每种方法的优点/缺点是什么?
- 哪种方法更惯用F#?
推荐答案
这取决于我们在谈论哪种错误.基本上有三种:
It depends on what kind of error we are talking about. Basically there are three kinds:
- 域错误(例如,用户提供的无效数据,使用此电子邮件的用户已注册等)
- 基础架构错误(例如,您无法连接到另一个微服务或数据库)
- 由程序员的错误引起的恐慌(例如
NullReferenceException
或StackOverflowException
等).
- Domain errors (e.g. user provided invalid data, user with this email is already registered, etc.)
- Infrastructure errors (e.g you can't connect to another microservice or DB)
- Panics (e.g.
NullReferenceException
orStackOverflowException
etc.), which are caused by programmers' mistakes.
尽管两种方法都能完成工作,但是通常您需要考虑的是使代码尽可能具有自记录性并易于阅读.这意味着:
While both approaches can get the job done, usually your concern should be to make your code as self-documented and easy-to-read as possible. Which means the following:
- 域错误:肯定适用于
Result
.这些错误"是预期的,它们是您工作流程的一部分.使用Result
可以在功能的签名中反映您的业务规则,这非常有用. - 基础结构故障:.如果您有微服务,则可能是那些失败的预料,并且使用
Result
可能会更方便.如果不是,请寻求例外. - Panics:肯定是
Exception
.首先,您无法使用Result
覆盖所有内容,您将需要使用两种方法中的全局异常过滤器.第二件事-如果您试图掩盖所有可能的紧急情况-代码将很快变得令人讨厌,这将使使用Result
处理域错误的全部事情丧命.
- Domain errors: definitely go for
Result
. Those "errors" are expected, they are part of your workflow. UsingResult
reflects your business rules in function's signature, which is very useful. - Infrastructure failures: it depends. If you have microservices, then probably those failures are expected and maybe it would be more convenient to use
Result
. If not -- go for exceptions. - Panics: definitely
Exception
. First of all, you can't cover everything withResult
, you gonna need global exception filter either way. Second thing -- if you try to cover all possible panics - code becomes a nasty disaster extremely fast, that will kill the whole point of usingResult
for domain errors.
因此,这实际上与Async
或C#互操作无关,它与代码的可读性和可维护性有关.
至于C#iterop,请放心,Result
具有所有帮助方法,例如IsError
等.但您始终可以添加扩展方法:
So really this has nothing to do with Async
or C# interop, it's about code readability and maintainability.
As for C# iterop -- don't worry, Result
has all the methods to help, like IsError
and so on. But you can always add an extension method:
[<AutoOpen>]
module Utils =
type Result<'Ok, 'Error> with
member this.Value =
match this with
| Ok v -> v
| Error e -> Exception(e.ToString()) |> raise
[<AutoOpen>]
module Utils =
type Result<'Ok, 'Error> with
member this.Value =
match this with
| Ok v -> v
| Error e -> Exception(e.ToString()) |> raise
这篇关于结果与提高F#异步?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!