Поскольку KeyPath
не может быть приведен к супертипам в Swift, я хочу написать стертую версию, которая представляет собой KeyPath
, значение которого может быть приведено к определенному протоколу или супертипу:
public struct PropertyGetter<Root, ValueType> {
private let keyPath: PartialKeyPath<Root>
public init<T: ValueType>(_ keyPath: KeyPath<Root, T>) {
self.keyPath = keyPath
}
public func get(_ instance: Root) -> ValueType {
return instance[keyPath: self.keyPath] as! ValueType
}
}
Компилятор справедливо жалуется, что
тип 'T' ограничен непротокольным типом не типа 'ValueType.Type'
как ValueType
потенциально может быть структурным типом.
Итак, как нам правильно ограничить это? Это означает, что
ValueType
является либо типом класса, либо протоколом, т.е. подклассифицируемый / реализуемый T
ограничен для соответствия ValueType
, т.е. x as! ValueType
должен гарантированно работать, где x: T
Обратите внимание, что действительно возможно написать такую структуру стирания типов, когда тип протокола фиксирован. Например, класс, который принимает только KeyPath
s, указывающие на CustomStringConvertible
членов:
public struct CustomStringConvertibleGetter<Root> {
private let keyPath: PartialKeyPath<Root>
public init<T: CustomStringConvertible>(_ keyPath: KeyPath<Root, T>) {
self.keyPath = keyPath
}
public func get(_ instance: Root) -> CustomStringConvertible {
return instance[keyPath: self.keyPath] as! CustomStringConvertible
}
}
let getter1 = CustomStringConvertibleGetter(\SomeClass.someString) // works
let getter2 = CustomStringConvertibleGetter(\SomeClass.nonConformingMember) // will throw an error at compile time