我可以制作像ExpressibleByKeyPathLiteral这样的东西吗?

时间:2019-03-11 20:33:30

标签: ios swift

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的类型相同,而实用性非常有限。)

0 个答案:

没有答案