首先,我有这段代码,它工作得很好:
protocol ComponentAccessible {}
extension ComponentAccessible {
func components<each T>(_ keyPaths: repeat KeyPath<Self, each T>) -> (repeat each T) {
{ (repeat self[keyPath: each keyPaths]) }
}
}
// MARK: - Usage
extension URL: ComponentAccessible {}
url.components(\.scheme, \.host, \.path)
但现在我想尝试一种稍微不同的方法(利用
PartialKeyPath
):
extension ComponentAccessible {
func components<each T>(_ keyPaths: PartialKeyPath<Self>...) -> (repeat each T) {
keyPaths.map { self[keyPath: $0] }
}
}
这无法编译,因为我返回的是一个数组,而不是一个元组。
首先,这不是类型安全的。
PartialKeyPath
不知道键路径值的类型,只知道根的类型。因此,为了能够返回 (repeat each T)
,您需要进行投射。
其次,
keyPaths
、PartialKeyPath<Self>...
的类型不是包扩展。它需要是一个包扩展,以便您能够返回具有匹配数量的元素的元组。
所以你需要类型包
each T
出现在keyPaths
的类型中somewhere,这样你就可以为
keyPaths
的类型编写包扩展,即调用者has传入类型他们想要这样或那样。
此时,您应该意识到您应该继续使用
KeyPath<Root, Value>
,因为您可以在那里直接使用each T
。如果您想要“语法练习”,您可以使用一对 PartialKeyPath<Self>
和元类型。
extension ComponentAccessible {
func components<each T>(keyPaths: repeat (PartialKeyPath<Self>, (each T).Type)) -> (repeat each T) {
(repeat self[keyPath: (each keyPaths).0] as! each T)
}
}
您也无法返回
Any
的元组。虽然您可以通过编写类型别名“欺骗”编译器认为您正在使用类型包,但编译器稍后仍会“查看您在做什么”。这些不起作用:
typealias A<X> = Any
typealias PKP<X, Y> = PartialKeyPath<X>
// now you can write (repeat A<each T>) to mean a variadic tuple of Anys, but...
extension ComponentAccessible {
// the compiler can see that you are not using T anywhere,
// and no, you cannot add a dummy metatype parameter with a default value
// parameter pack parameters cannot have default values
func components<each T>(keyPaths: repeat PKP<Self, each T>) -> (repeat each A<each T>) {
(repeat self[keyPath: each keyPaths])
}
// the compiler cannot form the constraint that keyPaths should have the same shape as the return type
func components<each T>(keyPaths: repeat PKP<Self, each T>) -> (repeat each T) {
(repeat self[keyPath: each keyPaths] as! each T)
}
}