我正在使用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) throws -> _
的实际定义需要Request.put(_:use:)
时,Xcode为什么说预期的类型是(Request) throws -> T
?这是如何使T
成为Future<Person>
和Future<Person?>
的?
你在这里打电话的.first
方法:
return connection.raw("Other long SQL query")
.binds([...])
.first(decoding: Person.self)
返回Future<Optional<Person>>
或Future<Person?>
。路由处理程序的返回类型是Future<Person>
,因此返回类型不正确。但即使您确实更改了处理程序的返回类型,也无法修复它。
你的主要问题是你不能从路由处理程序返回一个可选项,因为Optional
绝不符合ResponseEncodable
。如果您愿意,可以自己添加一致性。
如果您不想添加一致性,则可以在解码查询结果后使用.unwrap(or:)
方法:
return connection.raw("Other long SQL query")
.binds([...])
.first(decoding: Person.self)
.unwrap(or: Abort(.notFound))
这将检查以后的值是否存在。如果是,则传递该值。否则,未来的链接收您传入的错误,而不是返回。