我可以像ExpressibleByKeyPathLiteral一样强制编译器为我装箱我的KeyPaths吗?或者这些协议使用了某种编译器魔法来使它们工作吗?
问题: Swift有ExpressibleBy*Literal协议族,允许编译器autoBox某些类型,如下所示:
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))有没有办法做到这一点?(我知道我可以让它与泛型一起工作,但前提是所有的KeyPaths都是同一类型的,这是非常有限的实用工具)。
发布于 2019-03-12 23:08:44
我相信你在这里需要的是Variadic Generics,它在Swift中还不存在,但将来可能会存在。
作为一种变通方法,您可以创建采用一个键路径、两个键路径、三个键路径等的方法版本,直到您认为合理需要使用的最大数量(然后可能再使用一个)。您可以通过使用Sourcery生成变体来节省一些时间。
https://stackoverflow.com/questions/55109964
复制相似问题