在 Dictionary/HashMap 中存储 KeyPath
Storing KeyPaths in Dictionary/HashMap
我在散列 ReferenceWritableKeyPath
时遇到问题。散列函数似乎在对密钥路径进行散列时也考虑了 ReferenceWritableKeyPath
的通用属性。我已经包含了示例代码来说明为什么这是一个问题:
struct TestStruct<T> {
// This function should only be callable if the value type of the path reference == T
func doSomething<Root>(object: Root, path: ReferenceWritableKeyPath<Root, T>) -> Int {
// Do something
print("Non-optional path: \(path) \(path.hashValue)")
return path.hashValue
}
}
let label = UILabel()
let textColorPath = \UILabel.textColor
let testStruct = TestStruct<UIColor>()
let hash1 = testStruct.doSomething(object: label, path: \.textColor)
let hash2 = textColorPath.hashValue
print("Optional path: \(textColorPath) \(hash2)")
如果您 运行 上面的代码,您会注意到 hash1 和 hash2 是不同的,尽管它们是指向相同 属性 UILabel 的路径。
这是因为第一个 ReferenceWritableKeyPath
有一个 Value
即 UIColor
而第二个 ReferenceWritableKeyPath
有一个 Value
即 Optional<UIColor>
我的项目要求将 ReferenceWritableKeyPath
存储在字典中,以便关联对象 (UILabel) 的每个 属性 只有一个 keyPath。由于哈希值不同,这意味着相同的路径将在字典中存储为 2 个不同的键。
有谁知道我可以使用它的方法吗?
~提前致谢
使textColorPath
也成为非可选的,以匹配:
let textColorPath = \UILabel.textColor!
或明确类型:
let textColorPath: ReferenceWritableKeyPath<UILabel, UIColor> = \.textColor
潜在的问题是 \.textColor
是一个隐式展开的可选而不是“真正的”可选。在某些情况下,它被视为基础类型,而在其他情况下,它被提升为可选类型。它是一个隐式解包可选的原因是因为将 textColor
设置为 nil 是合法的。但是你读到的值永远不会是nil。
正如@Rob Napier 指出的那样,问题出在泛型类型本身。我解决问题的方法是将 doSomething
分成两个单独的方法:
func doSomething<Root>(object: Root, path: ReferenceWritableKeyPath<Root, T?>) -> Int {
// Do something
print("Non-optional path: \(path) \(path.hashValue)")
return path.hashValue
}
func doSomething<Root>(object: Root, path: ReferenceWritableKeyPath<Root, T>) -> Int {
// Do something
print("Non-optional path: \(path) \(path.hashValue)")
return path.hashValue
}
当 T
是一个可选类型时,第一个将被调用,例如上面的示例(其中 UIColor
可以是 nil)。当 keyPath 指向 non-optional 属性 时调用第二个。 Swift 非常聪明,所以我猜它能够找出调用哪个方法,尽管它们几乎重复 headers.
我在散列 ReferenceWritableKeyPath
时遇到问题。散列函数似乎在对密钥路径进行散列时也考虑了 ReferenceWritableKeyPath
的通用属性。我已经包含了示例代码来说明为什么这是一个问题:
struct TestStruct<T> {
// This function should only be callable if the value type of the path reference == T
func doSomething<Root>(object: Root, path: ReferenceWritableKeyPath<Root, T>) -> Int {
// Do something
print("Non-optional path: \(path) \(path.hashValue)")
return path.hashValue
}
}
let label = UILabel()
let textColorPath = \UILabel.textColor
let testStruct = TestStruct<UIColor>()
let hash1 = testStruct.doSomething(object: label, path: \.textColor)
let hash2 = textColorPath.hashValue
print("Optional path: \(textColorPath) \(hash2)")
如果您 运行 上面的代码,您会注意到 hash1 和 hash2 是不同的,尽管它们是指向相同 属性 UILabel 的路径。
这是因为第一个 ReferenceWritableKeyPath
有一个 Value
即 UIColor
而第二个 ReferenceWritableKeyPath
有一个 Value
即 Optional<UIColor>
我的项目要求将 ReferenceWritableKeyPath
存储在字典中,以便关联对象 (UILabel) 的每个 属性 只有一个 keyPath。由于哈希值不同,这意味着相同的路径将在字典中存储为 2 个不同的键。
有谁知道我可以使用它的方法吗?
~提前致谢
使textColorPath
也成为非可选的,以匹配:
let textColorPath = \UILabel.textColor!
或明确类型:
let textColorPath: ReferenceWritableKeyPath<UILabel, UIColor> = \.textColor
潜在的问题是 \.textColor
是一个隐式展开的可选而不是“真正的”可选。在某些情况下,它被视为基础类型,而在其他情况下,它被提升为可选类型。它是一个隐式解包可选的原因是因为将 textColor
设置为 nil 是合法的。但是你读到的值永远不会是nil。
正如@Rob Napier 指出的那样,问题出在泛型类型本身。我解决问题的方法是将 doSomething
分成两个单独的方法:
func doSomething<Root>(object: Root, path: ReferenceWritableKeyPath<Root, T?>) -> Int {
// Do something
print("Non-optional path: \(path) \(path.hashValue)")
return path.hashValue
}
func doSomething<Root>(object: Root, path: ReferenceWritableKeyPath<Root, T>) -> Int {
// Do something
print("Non-optional path: \(path) \(path.hashValue)")
return path.hashValue
}
当 T
是一个可选类型时,第一个将被调用,例如上面的示例(其中 UIColor
可以是 nil)。当 keyPath 指向 non-optional 属性 时调用第二个。 Swift 非常聪明,所以我猜它能够找出调用哪个方法,尽管它们几乎重复 headers.