Swift 4泛型协议的map扩展方法:如何正确声明泛型参数?
解决Source协议的map扩展方法问题
首先确认你的Swift版本:
swift --version Swift version 4.1 (swift-4.1-RELEASE) Target: x86_64-unknown-linux-gnu
先回顾你现有的代码结构:
定义的协议与结构体
给定泛型生产者协议Source:
protocol Source { associatedtype T func produce() -> T }
用于类型转换的Mapping结构体:
struct Mapping<T, U : Source> : Source { typealias Transformation = (U.T) -> T private let upstream : U private let block : Transformation init(_ upstream: U, _ block : @escaping Transformation) { self.upstream = upstream self.block = block } func produce() -> T { return block(upstream.produce()) } }
生成静态文本的示例源TextSource:
struct TextSource : Source { private let text : String init(_ text: String) { self.text = text } func produce() -> String { return text } }
你当前可以通过直接初始化Mapping实现转换,但想要通过map方法链式调用,之前的两种方案都存在问题,下面给出正确的解决方案:
正确的map扩展写法
你需要利用Source协议的关联类型T,以及当前扩展的Self类型(即调用map方法的具体Source实现),正确的扩展代码如下:
extension Source { func map<T>(_ block: @escaping (Self.T) -> T) -> Mapping<T, Self> { return Mapping(self, block) } }
为什么之前的方案不行?
- 方案A的问题:你额外声明了泛型参数
U,但这个参数在函数签名里没有被实际使用——调用map的self本身就是一个符合Source的具体类型,也就是你原本想指定的U,所以编译器会报错“generic parameter 'U' is not used in function signature”。 - 方案B的问题:你引用了未声明的类型
U,U既不是当前扩展的泛型参数,也不是Source的关联类型,编译器自然找不到它。
验证使用
现在你可以像预期一样链式调用map了:
// 基础写法 let countSource = TextSource("Hi!").map { (text: String) -> Int in return text.count } print(countSource.produce()) // 输出: 3 // 简化写法(利用Swift类型推断) let simplifiedCount = TextSource("Hello").map { $0.count } print(simplifiedCount.produce()) // 输出: 5 // 链式多次转换 let chainedSource = TextSource("Swift") .map { $0.count } .map { "该字符串的长度是:\($0)" } print(chainedSource.produce()) // 输出: "该字符串的长度是:5"
内容的提问来源于stack exchange,提问作者znerol
相关产品推荐
相关产品推荐

