You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift Type Parameter Packs:如何返回元组而非数组?

解决PartialKeyPath版本components方法返回元组的编译问题

原可运行代码

最初基于KeyPath实现的版本可正常运行,借助可变泛型返回对应类型的元组:

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 {}
let url = URL(string: "https://example.com/path")!
url.components(\.scheme, \.host, \.path)

问题场景

尝试改用PartialKeyPath重写时,代码无法编译:

extension ComponentAccessible {
    func components<each T>(_ keyPaths: PartialKeyPath<Self>...) -> (repeat each T) {
        keyPaths.map { self[keyPath: $0] }
    }
}

编译失败核心原因:可变参数...会把传入的KeyPath打包成数组,map返回的也是数组类型,与方法声明的元组返回类型不匹配。

解决方案

要返回元组,必须放弃可变参数,改用可变泛型的repeat语法处理参数,同时处理PartialKeyPath取值后的类型转换:

基础实现(强制转换)

extension ComponentAccessible {
    func components<each T>(_ keyPaths: repeat PartialKeyPath<Self>) -> (repeat each T) {
        return (repeat self[keyPath: each keyPaths] as! each T)
    }
}
  • 用repeat语法接收任意数量的PartialKeyPath参数,对应构建相同元素数量的元组
  • 由于PartialKeyPath取值返回Any,需强制转换为泛型参数each T,调用时必须保证每个KeyPath对应的类型与泛型匹配,否则会触发运行时崩溃

安全实现(可选转换)

如果想避免运行时崩溃,可将返回类型改为可选元组:

extension ComponentAccessible {
    func components<each T>(_ keyPaths: repeat PartialKeyPath<Self>) -> (repeat each T?) {
        return (repeat self[keyPath: each keyPaths] as? each T)
    }
}

这种写法会将每个元素转换为对应类型的可选值,类型不匹配时返回nil,安全性更高。

使用示例

extension URL: ComponentAccessible {}
let url = URL(string: "https://example.com/path")!
let parts = url.components(\.scheme, \.host, \.path)
// 基础实现中,parts 类型为 (String?, String?, String)
// 安全实现中,parts 类型为 (String??, String??, String?)

内容的提问来源于stack exchange,提问作者Roman

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 18:40:20