swift - 为什么不能在 map 语句中使用键路径语法?

标签 swift swift-keypath

假设我有一个结构 AStruct:

struct AStruct {
    let name: String
    let value: Int
}

假设我有一个 AStruct 数组:

let array: [AStruct] = [
AStruct(name: "John", value: 1),
    AStruct(name: "Bob", value: 23),
    AStruct(name: "Carol", value: 17),
    AStruct(name: "Ted", value: 9),
    AStruct(name: "Alice", value: 13),
    AStruct(name: "Digby", value: 4)
]

现在假设我想使用 map() 从我的 AStruct 数组中创建一个整数数组。

此代码有效:

let values = array.map { $0.value }

但是如果我尝试使用 Swift 键路径语法,无论我尝试什么都会出错。示例:

let values = array.map { \.value }

我得到一个错误:

Cannot infer key path type from context; consider explicitly specifying a root type.

那我该怎么做呢?

如果我给输入一个名称和类型,我就能让它工作:

let values = array.map { (aVal: AStruct) -> Int in
    return aVal.value
}

但这显然不是关键路径语法。

最佳答案

SE-0249: Key Path Expressions as Functions是针对此功能的相关 Swift Evolution 提案,并且来自该提案:

As implemented in apple/swift#19448, occurrences of \Root.value are implicitly converted to key path applications of { $0[keyPath: \Root.value] } wherever (Root) -> Value functions are expected. For example:

users.map(\.email)

Is equivalent to:

users.map { $0[keyPath: \User.email] }

<截图>

When inferring the type of a key path literal expression like \Root.value, the type checker will prefer KeyPath<Root, Value> or one of its subtypes, but will also allow (Root) -> Value. If it chooses (Root) -> Value, the compiler will generate a closure with semantics equivalent to capturing the key path and applying it to the Root argument. For example:

// You write this:
let f: (User) -> String = \User.email

// The compiler generates something like this:
let f: (User) -> String = { kp in { root in root[keyPath: kp] } }(\User.email)

换句话说:编译器识别键路径表达式当作为直接参数传入到期望函数的位置时,并注入(inject)从键路径到生成的闭包的转换。当你写作时

array.map { \.value }

您正在传递一个闭包,其主体评估 到一个关键路径,因为关键路径对编译器来说似乎是任意的(例如,它没有类型 \.value 的上下文)根除),你会得到错误。


还需要注意的是:

The implementation is limited to key path literal expressions (for now), which means the following is not allowed:

let kp = \User.email // KeyPath<User, String>
users.map(kp)

我不记得此时此限制是否已解除,但如果您发现自己处于需要应用的键路径但自动转换不起作用的情况,则需要通过手动将键路径插入闭包,然后直接关闭该键路径。

关于swift - 为什么不能在 map 语句中使用键路径语法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72652593/

相关文章:

node.js - 使用 Swift 的 Socket.io 不是握手

ios - 从嵌入在 UINavigationController 中的一个 View Controller 转到另一个 UINavigationController

swift - 通过 KeyPath 设置数组的值

swift - 观察 Swift KeyPaths 列表

ios - Swift 将键路径作为函数的参数传递

swift - Xcode6 无法使用类型的参数列表调用 'subscript'

ios - 如何在 Swift 和 Alamofire 中将对象映射到对象内部的数组中

arrays - 在 swift 3 中将 [AnyObject] 转换为 [Int]

swift - 在 Swift 中动态分配 Struct 的属性