假设我有以下类:
class User: NSObject {
var name = "Fred"
var age = 24
var email = "fred@freddy.com"
var married = false
}我希望能够编写一个泛型函数,它可以接收已知类类型的KeyPath列表,读取值并打印到屏幕上。问题是,我不能让下面的代码编译,因为KeyPath的Value的类型是未知的,并且每次都是不同的。我必须做什么才能使它通用地工作?
请考虑以下几点:
struct KeyPathProperties<T> {
var name: String
var relatedKeyPaths: [KeyPath<T, Any>]
}
extension KeyPath where Root == User {
var properties: KeyPathProperties<Root> {
switch self {
case \Root.name:
return KeyPathProperties(name: "name", relatedKeyPaths: [\Root.age, \Root.email])
default:
fatalError("Unknown key path")
}
}
}这一行无法编译:
return KeyPathProperties(name: "name", relatedKeyPaths: [\Root.age, \Root.email])出现以下错误:
Cannot convert value of type 'KeyPath<User, Int>' to expected element type 'KeyPath<User, Any>'
例如,这是我希望能够做的事情:
let myUser = User()
var keyPathProps = KeyPathProperties(name: "name", relatedKeyPaths: [\User.age, \User.email])
for keyPath in props.relatedKeyPaths {
print("Value: \(myUser[keyPath: keyPath])")
}当然,上面的代码不能编译。本质上,我希望在运行时将keyPaths存储在一个数组中,这样我通常可以在某个时间点从User中获取值。我需要知道我是否可以用某种方式重写上面的代码,这样编译器就可以在运行时安全而正确地确定keyPath的值的类型。
这是一个更复杂的架构问题的概念性用例,我希望用更少的代码来解决。
更多信息:
在运行时,我希望跟踪修改的属性-这些属性保存在每个对象/实例的modifiedProps数组中。在运行时的某个时刻,我希望能够枚举这个KeyPaths数组并打印它们的值,如下所示:
for modifiedKeyPath in self.modifiedProps {
print ("\(self[keyPath: modifiedKeyPath])"
}简而言之,我需要能够在KeyPathProperties中捕获KeyPath的泛型类型。我该如何实现这一点?
附注:我已经可以通过使用基于Swift 3样式字符串的KeyPaths (通过将@objc添加到类属性)轻松地实现这一点。我可以将keyPaths数组存储为字符串,然后执行以下操作:
let someKeyPath = #keyPath(User.email)
...
myUser.value(forKeyPath: someKeyPath)我一般不能用Swift 4 KeyPaths做到这一点。
发布于 2020-03-01 03:40:31
这个错误告诉你你的误解是什么:
Cannot convert value of type 'KeyPath<User, Int>'
to expected element type 'KeyPath<User, Any>'您似乎认为可以在需要KeyPath<User, Any>的地方使用KeyPath<User, Int>,表面上是因为Int是Any。但事实并非如此。这些是泛型类型,并且泛型类型不是协变的-也就是说,没有基于其参数化类型的泛型的替换原则。这两种类型实际上是不相关的。
如果您需要一个键路径数组,而不考虑它们的参数化类型,那么您将需要一个PartialKeyPath或AnyKeyPath数组。在您的用例中,根对象似乎始终是相同的,因此您可能需要PartialKeyPath。
https://stackoverflow.com/questions/60468740
复制相似问题