类型参数包:如何返回元组而不是数组?

问题描述 投票:0回答:1

首先,我有这段代码,它工作得很好:

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] }
    }
}

这无法编译,因为我返回的是一个数组,而不是一个元组。

swift generics variadic generic-type-parameters swift-keypath
1个回答
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)
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.