[英]Why can't I use key path syntax in a map statement?
想象一下,我有一個結構 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 }
我收到一個錯誤:
無法從上下文推斷關鍵路徑類型; 考慮明確指定根類型。
那我該怎么做?
如果我給輸入一個名稱並輸入,我可以讓它工作:
let values = array.map { (aVal: AStruct) -> Int in
return aVal.value
}
但這顯然不是關鍵路徑語法。
SE-0249: Key Path Expressions as Functions是該功能的相關 Swift Evolution 提案,並且來自該提案:
正如在 apple/swift#19448 中實現的那樣,
\Root.value
的出現被隱式轉換為{ $0[keyPath: \Root.value] }
的鍵路徑應用程序,無論是(Root) -> Value
函數。 例如:users.map(\.email)
相當於:
users.map { $0[keyPath: \User.email] }
<剪輯>
在推斷諸如
\Root.value
之類的鍵路徑文字表達式的類型時,類型檢查器將首選KeyPath<Root, Value>
或其子類型之一,但也允許(Root) -> Value
。 如果它選擇(Root) -> Value
,編譯器將生成一個閉包,其語義等同於捕獲鍵路徑並將其應用於 Root 參數。 例如:// 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)
換句話說:編譯器在作為預期函數的直接參數傳入時識別鍵路徑表達式,並將從鍵路徑的轉換注入到生成的閉包。 當你寫
array.map { \.value }
您正在傳入一個閉包,其主體評估為鍵路徑,並且因為鍵路徑對編譯器來說似乎是任意的(例如,它沒有關於\.value
根植於什么類型的上下文),您會收到錯誤.
另外需要注意的是:
實現僅限於鍵路徑文字表達式(目前),這意味着不允許以下內容:
let kp = \User.email // KeyPath<User, String> users.map(kp)
我不記得此時此限制是否已取消,但如果您發現自己處於需要應用密鑰路徑但自動轉換不起作用的情況,則需要將密鑰路徑傳遞給手動關閉,然后直接關閉該密鑰路徑。
SE-0249允許將關鍵路徑視為閉包。 map
需要一個“ (Element) throws -> T
”——例如,在你的情況下,這個:
{ $0.value } as (AStruct) -> _
但關鍵路徑不是封閉。 所以你不能把它當作一個……
array.map { (\.value)($0) }
…除非你明確地輸入它:
array.map { (\.value as (_) -> _)($0) }
但你永遠不會那樣做。 原本的
array.map { $0.value }
語法更好。 但是,將關鍵路徑轉換為閉包的最常見方法是更好看。
array.map(\.value)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.