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
相关产品推荐
相关产品推荐

