【问题标题】:Type mismatch in async method异步方法中的类型不匹配
【发布时间】:2021-11-26 22:54:38
【问题描述】:

我正在编写一个异步方法,它应该异步查询端口,直到找到一个端口,或者在 5 分钟后超时;

    member this.GetPort(): Async<Port> = this._GetPort(DateTime.Now)

    member this._GetPort(startTime: DateTime): Async<Port> = async {
        match this._TryGetOpenPort() with
        | Some(port) -> port
        | None -> do
            if (DateTime.Now - startTime).TotalMinutes >= 5 then
                raise (Exception "Unable to open a port")
            else
                do! Async.Sleep(100)
                let! result = this._GetPort(startTime)
                result}

    member this._TryGetOpenPort(): Option<Port> = 
        // etc.

但是,我在_GetPort 中发现了一些奇怪的类型不一致;该函数说我返回的是Async&lt;unit&gt;而不是Async&lt;Port&gt;

【问题讨论】:

    标签: asynchronous types f# timeout matching


    【解决方案1】:

    这有点不直观,但是让你的代码工作的方法是这样的:

    member private this.GetPort(startTime: DateTime) =
        async {
            match this.TryGetOpenPort() with
            | Some port ->
                return port
            | None ->
                if (DateTime.Now - startTime).TotalMinutes >= 5 then
                    raise (Exception "Unable to open a port")
                
                do! Async.Sleep(100)
                let! result = this.GetPort(startTime)
                return result
        }
    
    member private this.TryGetOpenPort() = failwith "yeet" // TODO
    

    我冒昧地清理了一些东西并将成员设为私有,因为这似乎是您在这里主要追求的内容,并通过更详细的内部方式获取端口。

    您的代码未编译的原因是因为您在计算中与returning 不一致:

    • Some(port) 的情况下,您缺少 return 关键字 - 这是将值提升回 Async&lt;port&gt; 所必需的
    • 您引发异常的if 表达式有一个else 分支,但您不是来自两者的return。在这种情况下,由于您显然不希望返回任何内容而只是引发异常,因此您可以省略 else 并使其成为命令式程序流,就像在非异步代码中一样。

    您可能希望考虑的另一件事是如果抛出异常是您想要的,或者只是返回 Result&lt;T,Err&gt; 或选项是正确的调用。异常本身并不是坏事,但如果有一种很好的方法可以为包装返回值的类型赋予意义,那么很多 F# 编程通常会避免使用它们。

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-05-23
    • 2021-06-24
    • 1970-01-01
    • 2019-06-04
    • 2023-03-17
    • 1970-01-01
    • 2019-04-05
    相关资源
    最近更新 更多