【问题标题】:Why Xcode keeps substituting generics with '_'为什么 Xcode 一直用 '_' 代替泛型
【发布时间】:2019-09-09 08:38:30
【问题描述】:

我正在使用 Swift 5 和 Vapor 3 制作服务器。在设置路由时,我想从我的控制器调用一个函数,该函数返回一个可选值,如下所示:

//Person.swift

struct Person: Content {
    ...
}
//PersonController.swift

func update(_ request: Request) throws -> Future<Person> {
    let uuid = try request.parameters.next(UUID.self)

    return try request.content.decode(Person.self).flatMap { content in
        request.withPooledConnection(to: DatabaseIdentifier<PostgreSQLDatabase>.psql) { connection in
            /*
            *  No code completion beyond this point,
            *  even connection appears as type '_' instead of
            *  PostgreSQLConnection (not relevant to the question tho,
            *  just worth noting)
            */
            if content.lastName != nil {
                return connection.raw("Very long SQL query...")
                .binds([...])
                .first(decoding: Person.self)
            }

            return connection.raw("Other long SQL query")
            .binds([...])
            .first(decoding: Person.self)
        }
    }

}
router.put("people", UUID.parameter, use: personController.update)

然后我得到这个错误

Cannot convert value of type '(Request) throws -> EventLoopFuture<Person?>' to expected argument type '(Request) throws -> _'

在使用 Vapor 时,我看到很多情况,其中 Xcode 放弃了自动完成功能,所有内容都输入为 _。主要在用作回调的闭包内部。这很烦人,坦率地说,我不确定它是由 Vapor、Swift 还是 Xcode 引起的。这是一个巨大的 PITA,但一旦我编译,一切都会得到解决,类型会被整理出来。但是在这种情况下,它只是不起作用。

所以问题是:当Request.put(_:use:) 的实际定义需要(Request) throws -&gt; T 时,为什么Xcode 会说预期的类型是(Request) throws -&gt; _,这对TFuture&lt;Person&gt; 和@ 有何区别? 987654331@?

【问题讨论】:

  • 您能否在您的router 中显示您的EventLoopFuture 类和put 函数
  • @AdrianBobrowski 嗯不知道你在问什么,我猜put 函数是指personController.update 的内容,EventLoopFuture 类是指Person 类(实际上是是一个结构)。是这样吗?
  • 如果EventLoopFuture&lt;T&gt;Future&lt;T&gt; 兼容,那么您就有问题了,因为在您的情况下,您对T 使用了不同的类型。在EventLoopFuture 中,您使用Optional&lt;Person&gt;,在Future 中,您使用Person
  • 我有点明白,但Future 不仅仅是EventLoopFuture 的别名
  • @AdrianBobrowski 我更新了问题以包含update 函数(由Router.put 调用)的内容,我认为这就是您所指的。

标签: swift xcode generics vapor server-side-swift


【解决方案1】:

您在此处调用的.first 方法:

return connection.raw("Other long SQL query")
.binds([...])
.first(decoding: Person.self)

返回Future&lt;Optional&lt;Person&gt;&gt;Future&lt;Person?&gt;。您路由处理程序的返回类型是Future&lt;Person&gt;,因此您的返回类型不正确。但即使您确实更改了处理程序的返回类型,也无法解决问题。

您的主要问题是您不能从路由处理程序返回一个可选项,因为Optional 绝不会符合ResponseEncodable。如果您愿意,您可以自己添加一致性。

如果你不想添加一致性,你可以在解码查询结果后使用.unwrap(or:)方法:

return connection.raw("Other long SQL query")
.binds([...])
.first(decoding: Person.self)
.unwrap(or: Abort(.notFound))

这将检查将来的值是否存在。如果是,则传递该值。否则,future 链会收到您传入的错误并将其返回。

【讨论】:

  • 好的对不起我打错了实际上返回已经是Future&lt;Person?&gt;但正如你所说的那样实际上是导致所描述的错误的原因所以我想我必须解开这个值,这就是我的意思试图避免。但是我不明白为什么 Xcode 没有将不是 ResponseEncodable 标记为错误,而是放弃代码完成。
  • Swift 的类型检查器在闭包方面并不是那么好。将一些协议添加到混合中,肯定会出现问题。请记住,如果您遇到任何错误,就像您刚才所做的那样,任何事情都可能是错误的?
  • 所以,虽然你可以责怪 Vapor 为你必须使用的所有闭包,但这确实是 Swift 的错。
  • 是的,自从 Swift 4.0 发布以来我就没有使用过,该死的它变得如此奇怪。当您强制单击某个标识符时,Xcode 也曾经显示文档,我一直认为这很好,但它在很久以前就停止了(还没有找到一个设置来恢复它)。比起那些奇怪的动态类型语言,我仍然更喜欢使用 Swift ?。
猜你喜欢
  • 1970-01-01
  • 2010-09-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-11
  • 2015-12-30
  • 2010-09-27
  • 2011-08-07
相关资源
最近更新 更多