【问题标题】:How to wait on a future that returns void?如何等待一个返回无效的未来?
【发布时间】:2020-05-17 23:45:25
【问题描述】:

我正在关注“Server Side Swift Vapor Edition”一书,并且正在尝试第 174 页的练习。

我有一个名为 Poll 的结构,定义如下:

struct Poll: Content, SQLiteUUIDModel, Migration {
    var id: UUID?
    var title: String
    var option1: String
    var option2: String
    var votes1: Int
    var votes2: Int
}

它被映射到一个带有 Fluent 的 SQLite 数据库中,我正在尝试编写一个给出这样一个发布请求的路由:

localhost:8080/polls/delete/

能够在数据库中找到 poll 对象,如果不存在则返回错误,如果存在则删除。这就是我目前解决问题的方式:

router.post("polls", "delete", UUID.parameter) { req -> Future<Poll> in
    let id = try req.parameters.next(UUID.self)

    return Poll.find(id, on: req).map(to: Poll.self) { poll in
        guard let poll = poll else {
            throw Abort(.notFound)
        }

        poll.delete(on: req)

        return poll
    }
}

让我们分解一下:

  1. 我读取了在 post 请求中传递的 UUID(例如 http://localhost:8080/polls/delete/FBF7FDC2-0ECB-4C1F-AD8F-A62DE68E531B
  2. 我试图找到投票
  3. 如果 poll 对象为 nil(表示未找到),我会抛出 404 not found 错误
  4. 如果我找到它,我会删除投票并将其返回

这行得通。我可以使用这条路线删除民意调查。 但是我有一些疑问:

  1. 会不会是delete方法还是失败了? (例如,由于内部 SQLite 错误)
  2. 如果是,我可以等到投票实际删除后再返回吗?

问题是delete方法返回一个EventLoopF​​uture类型的对象。如果它是 tupe EventLoopF​​uture 的对象,我将能够轻松地将其映射到民意调查。但是由于模板参数是无效的,如果我这样修改代码:

router.post("polls", "delete", UUID.parameter) { req -> Future<Poll> in
    let id = try req.parameters.next(UUID.self)

    return Poll.find(id, on: req).flatMap(to: Poll.self) { poll in
        guard let poll = poll else {
            throw Abort(.notFound)
        }

        return poll.delete(on: req).flatMap(to: Poll.self) { poll -> EventLoopFuture<Poll> in
            return poll
        }
    }
}

我收到一个语法错误:“无法将 'Void' 类型的值转换为闭包结果类型 'EventLoopF​​uture'”。看起来我无法将 EventLoopF​​uture 对象映射到 EventLoopF​​uture。问题只是我想在返回之前等待删除操作完成。有什么解决办法吗?

【问题讨论】:

  • return poll.delete(on: req).transform(to: poll)
  • @imike, transform 忽略了现有的Future 值,所以它会等到delete 完成吗?
  • transform 总是等待未来,所以它会等到delete 完成

标签: swift fluent vapor fluentsqlite


【解决方案1】:

delete 函数返回Void,所以你的闭包不应该有参数,这是你得到语法错误的原因之一。试试这个:

router.post("polls", "delete", UUID.parameter) { req -> Future<Poll> in
    let id = try req.parameters.next(UUID.self)

    return Poll.find(id, on: req).flatMap { poll in
        guard let poll = poll else {
            throw Abort(.notFound)
        }

        return poll.delete(on: req).flatMap{
            return request.future(poll)
        }
    }
}

将 OP 的 cmets 带到 @Rob Napier 的答案板上,这应该将您的 poll 转换回未来,但只有在 delete 完成之后。

【讨论】:

  • 我收到一个错误:无法将类型 '(_) throws -> EventLoopF​​uture' 的值转换为预期的参数类型 '(Request) throws -> _'
  • 经过我的编辑后,您应该不会收到错误(或者至少肯定不会出现这个错误!)。
  • 您可以将最终的 flatMap 更改为地图,并且无需在将来包装返回的民意调查
猜你喜欢
  • 2017-10-03
  • 2017-02-10
  • 1970-01-01
  • 2014-02-20
  • 2012-08-22
  • 1970-01-01
  • 1970-01-01
  • 2021-07-17
相关资源
最近更新 更多