TLDR:我可以做类似ExpressibleByKeyPathLiteral
的事情来强迫编译器为我装箱我的KeyPath,还是这些协议使用某种编译器魔术使它们起作用?
问题:
Swift具有ExpressibleBy*Literal
系列协议,可让编译器自动对某些类型进行自动装箱,例如:
struct Box: ExpressibleByIntegerLiteral {
typealias IntegerLiteralType = Int
let value: IntegerLiteralType
init(integerLiteral value: IntegerLiteralType) {
self.value = value
}
}
func pbox(_ box: Box...) {
for b in box {
print(b)
}
}
pbox(1,2,3)
我想知道是否有必要为Swift Keypath
文字做等效的操作。例如,我有:
struct PartialEquatableKeyPath<Root> {
let keyPath: PartialKeyPath<Root>
let yieldsEqualValue: (Root, Root) -> Bool
init<Value: Equatable>(_ keyPath: KeyPath<Root, Value>) {
self.keyPath = keyPath
self.yieldsEqualValue = { $0[keyPath: keyPath] == $1[keyPath: keyPath] }
}
}
extension Equatable {
func isEqual(to other: Self, byComparing keyPaths:[PartialEquatableKeyPath<Self>]) -> Bool {
return keyPaths.allSatisfy { $0.yieldsEqualValue(self, other) }
}
}
我必须这样打电话:
let a = UIView()
let b = UIView()
b.isHidden = true
let keyPaths: [PartialEquatableKeyPath<UIView>] = [.init(\.isHidden), .init(\.frame)]
print(a.isEqual(to: b, byComparing: keyPaths))
我真正想要的是这样的东西:
extension Equatable {
func isEqual<SomeEquatable: Equatable>(_ other: Self, byComparing keyPaths:PartialEquatableKeyPath...) -> Bool {
return keyPaths.allSatisfy { $0.yieldsEqualValue(self, other) }
}
}
所以我可以这样称呼它:
let a = UIView()
let b = UIView()
b.isHidden = true
print(a.isEqual(b, byComparing: \.frame.origin.x, \.isHidden))
有没有办法做到这一点? (我知道我可以使它与泛型一起使用,但前提是所有KeyPath的类型相同,而实用性非常有限。)