2

自 Swift 4 以来,已经获得了subscript(keyPath:)可用于检索值的对象AnyKeyPath及其子类。根据Swift 书,下标is available on all types。例如,一个类的实例TestClass可以用AnyKeyPath类似这样的下标:

class TestClass {
    let property = true
}

let anyKeyPath = \TestClass.property as AnyKeyPath
_ = TestClass()[keyPath: anyKeyPath]

这可以按预期正确编译。使用任何其他有效的子类也可以编译,包括PartialKeyPath<TestClass>,KeyPath<TestClass, Bool>等。此功能在协议扩展中不可用。例如,以下内容无效:

class TestClass {
    let property = true
}

protocol KeyPathSubscriptable {

}

extension KeyPathSubscriptable {
    func test() {
        let anyKeyPath = \TestClass.property as AnyKeyPath
        _ = self[keyPath: anyKeyPath] // Value of type 'Self' has no subscripts
    }
}

如果我们想在协议中使用那个 keyPath 下标,我们可以将它包含在协议定义中。但是,编译器不会自动解析它:

protocol KeyPathSubscriptable {
    subscript(keyPath: AnyKeyPath) -> Any? { get }
}

extension KeyPathSubscriptable {
    func test() {
        let anyKeyPath = \TestClass.property as AnyKeyPath // This can be any valid KeyPath
        _ = self[keyPath: anyKeyPath]
    }
}

class TestClass: KeyPathSubscriptable { // Type 'TestObject' does not conform to protocol 'KeyPathSubscriptable'
    let property = true
}

有了这个,我们得到一个编译错误:Type 'TestObject' does not conform to protocol 'KeyPathSubscriptable'. 为了解决这个问题,我们必须在 中包含该下标的冗余实现TestClass

class TestClass: KeyPathSubscriptable {
    let property = true

    subscript(keyPath: AnyKeyPath) -> Any? {
        fatalError() // This is never executed
    }
}

这解决了一致性问题并产生了目标结果,尽管它看似不必要且不合逻辑。我不确定如何,但下标实现甚至从未使用过。它正在寻找并使用它的预期实现subscript(keyPath:),但是如何呢?那在哪里,有没有办法在协议中使用它?为什么编译器需要它,即使它从未使用过?

此用例的上下文位于日志记录模块中。目标是对象应该能够采用特定的协议,该协议无需对对象进行额外设置,就可以提供对象的人类可读性description,而不是许多对象的默认值,即内存地址。该协议将使用 Mirror 来获取KeyPath对象的 s、读取值并将它们打印到控制台。它用于调试目的,不会在任何生产环境中运行。

如果我能做出任何澄清,请告诉我。如果其他人认为这可能是某种错误,我可能会将其发布给 Swift 团队。感谢所有帮助。提前致谢。

完整的要点位于此处

4

0 回答 0