[英]Swift Keypath Generic and Subclassing
I'm working on a class where a superclass and its subclasses have varying properties, but all of the same type that need identical processing before being assigned.我正在研究一个超类及其子类具有不同属性的类,但所有相同的类型在分配之前都需要相同的处理。 I've come up with a quite contrived and simplified example of what I'm trying to do with key paths, possibly using generics, including a non optimal, yet working variation.我想出了一个非常人为和简化的例子,说明我试图对关键路径做些什么,可能使用泛型,包括非最佳但有效的变体。
class OriginalClass {
// this will only allow for properties that exist available on the base `OriginalClass` (and that makes sense)
func updateAProperty(to value: Int, keyPath: ReferenceWritableKeyPath<OriginalClass, Int>) {
// lots of custom, but common logic
self[keyPath: keyPath] = value
}
// this *works*, but I don't like the cast I have to do on the first line, and the call site requires explicit
// keypaths (including the type)
func updateAPropertyTwo<GenClass>(to value: Int, keyPath: ReferenceWritableKeyPath<GenClass, Int>) {
guard let self = self as? GenClass else { return }
self[keyPath: keyPath] = value
}
// ideally, i want to do something like this. Basically, the compiler should (aka i WANT it to) be able to tell that
// im working off a subclass of OriginalClass and provide the keypaths available to the subclass in addition to those
// on the base, superclass.
// func idealNonworking(to value: Int, keyPath: ReferenceWritableKeyPath<*AutomaticallyReplacedWithWhateverSubclass*, Int>) {
// // lots of custom, but common logic
// self[keyPath: keyPath] = value
// }
// this complains that `Same-type requirement makes generic parameter 'GenClass' non-generic`, but afaik, if it DID
// work it SHOULD include the subclass properties (but it doesn't, to be clear)
// func alternativeIdealYetNonworking<GenClass>(to value: Int, keyPath: ReferenceWritableKeyPath<GenClass, Int>) where GenClass == Self {
// // lots of custom, but common logic
// self[keyPath: keyPath] = value
// }
}
class SecondClass: OriginalClass {
var subclassValue = 0
func nonWorkingExample() {
// updateAProperty(to: subclassValue + 1, keyPath: \.subclassValue)
}
func subOptimalWorkingExample() {
updateAPropertyTwo(to: subclassValue + 1, keyPath: \SecondClass.subclassValue)
// updateAPropertyTwo(to: subclassValue + 1, keyPath: \Self.subclassValue) // runs into a runtime demangling error
// updateAPropertyTwo(to: subclassValue + 1, keyPath: \.subclassValue)
}
// func optimalYetNonworkingExample() {
// idealNonworking(to subclassValue + 1, keyPath: \.subclassValue)
// }
}
let test = SecondClass()
print(test.subclassValue)
test.subOptimalWorkingExample()
print(test.subclassValue)
Now, I know WHY the first one won't work (the key path type is defined by the properties available on OriginalClass
), but I'm not sure why the last one wouldn't work.现在,我知道为什么第一个不起作用(关键路径类型由OriginalClass
可用属性定义),但我不确定为什么最后一个不起作用。 Of course, that's less important than if someone knows how to do this当然,这比是否有人知道如何做到这一点更重要
Self
is allowed in protocol extensions, so I wrote just that: Self
在协议扩展中是允许的,所以我只写了:
protocol P {
// put whatever methods and properties from OriginalClass the "lots of custom,
// but common logic" need here...
}
class OriginalClass : P {}
extension P {
func updateAProperty(to value: Int, keyPath: ReferenceWritableKeyPath<Self, Int>) {
// lots of custom, but common logic
self[keyPath: keyPath] = value
}
}
And usage:和用法:
class SecondClass: OriginalClass {
var subclassValue = 0
func workingExample() {
updateAProperty(to: subclassValue + 1, keyPath: \.subclassValue)
}
}
let test = SecondClass()
print(test.subclassValue)
test.workingExample()
print(test.subclassValue)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.