我有一个枚举案例数组,其中每个案例都有一个keyPath
属性,它返回AnyKeyPath
与枚举案例同名的匹配类属性:
protocol PathAccessor: CodingKey {
var keyPath: AnyKeyPath { get }
static var allCases: [Self] { get }
init?(rawValue: Int)
}
extension PathAccessor {
static var allCases: [Self] {
var cases: [Self] = []
var index: Int = 0
while let element = Self.init(rawValue: index) {
cases.append(element)
index += 1
}
return cases
}
}
class Robot {
let name: String
var age: Int
var powered: Bool
var hasItch: Bool?
enum CodingKeys: Int, PathAccessor {
case name
case age
case powered
case hasItch
var keyPath: AnyKeyPath {
switch self {
case .name: return \Robot.name
case .age: return \Robot.age
case .powered: return \Robot.powered
case .hasItch: return \Robot.hasItch
}
}
}
init(name: String, age: Int, powered: Bool) {
self.name = name
self.age = age
self.powered = powered
}
}
for element in Robot.CodingKeys.allCases {
// Trying to implement
}
在上面的循环中,我想检查keyPath
case 的属性,看它是否是 a WritableKeyPath
,如果是,则创建一个闭包来修改键路径访问的属性。
问题在于 aWritableKeyPath
是泛型类型。我知道Root
类型,但Value
类型几乎可以是现有的任何类型。我可以为每种最可能的类型创建一堆案例:
if let path = element.keyPath as? WritableKeyPath<Robot, Int> {
} else if let path = element.keyPath as? WritableKeyPath<Robot, String> {
} // So on and so forth
但这是耗时、丑陋且难以维护的。
我确实尝试强制转换为动态类型,但这会产生编译器错误(Use of undeclared type 'valueType'
):
let valueType = type(of: element.keyPath).valueType
guard let path = element.keyPath as? WritableKeyPath<Self, valueType> else {
continue
}
我可以使用类型已经符合的协议,但由于某种原因,这也失败了:
guard let path = element.keyPath as? WritableKeyPath<Robot, NodeInitializable> else {
print("bad")
continue
}
print("good")
// Output:
// bad
// bad
// bad
// bad
那么,是否有可能在没有大量解包语句或不应该在生产中使用的奇怪技巧的情况下将 a转换AnyKeyPath
为 a ?WritableKeyPath