swift --version
Swift version 4.1 (swift-4.1-RELEASE)
Target: x86_64-unknown-linux-gnu
给定一个定义通用生产者的简单协议(来源):
protocol Source {
associatedtype T
func produce() -> T
}
能够在源类型之间进行转换的映射:
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())
}
}
产生静态文本的示例源:
struct TextSource : Source {
private let text : String
init(_ text: String) {
self.text = text
}
func produce() -> String {
return text
}
}
我可以用它来计算,例如,计算字符......
let t = TextSource("Hi!")
let f = Mapping(t, { (text: String) -> Int in
return text.count
})
print(f.produce()) // output: 3
但我更喜欢在map
上使用通用Source
扩展函数,以便可以链接转换,例如:
let t = TextSource("Hi!").map { (text: String) -> Int in
return text.count
}
接近A
extension Source {
func map<T, U : Source>(_ block: @escaping Mapping<T, U>.Transformation) -> Source {
return Mapping(self, block)
}
}
swift编译器拒绝了这一点:
error: generic parameter 'U' is not used in function signature
func map<T, U : Source>(_ block: @escaping Mapping<T, U>.Transformation) -> Source {
^
方法B
extension Source {
func map<T>(_ block: @escaping Mapping<T, U>.Transformation) -> Source {
return Mapping(self, block)
}
}
在这种情况下,编译器会抱怨缺少类型参数:
error: use of undeclared type 'U'
func map<T>(_ block: @escaping Mapping<T, U>.Transformation) -> Source {
^
问题
为了满足编译器需要在map
扩展函数上指定哪些类型参数和约束?
答案 0 :(得分:1)
您不能将Source
用作map
的具体返回类型,因为它是具有关联类型要求的协议。
要解决此问题,您可以让map
函数返回Mapping<X, Self>
:
extension Source {
func map<Result>(_ transform: @escaping (T) -> Result) -> Mapping<Result, Self> {
return Mapping(self, transform)
}
}
该功能现在有Self
的要求。生成的Mapping
类型具有泛型类型参数Self
,该参数由Source
的具体实现替换,例如Mapping
。 TextSource
或{{1}}。