swift - 通用协议上的 Swift 4 扩展函数,它以通用函数作为参数
问题描述
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
为了满足编译器的要求,需要在扩展函数上指定哪些类型参数和约束?
解决方案
您不能将Source
其用作具体的返回类型,map
因为它是具有关联类型要求的协议。
为了解决这个问题,您可以使用map
函数 return Mapping<X, Self>
:
extension Source {
func map<Result>(_ transform: @escaping (T) -> Result) -> Mapping<Result, Self> {
return Mapping(self, transform)
}
}
该功能现在有一个Self
要求。结果Mapping
类型有一个泛型类型参数Self
,它被 的具体实现所取代Source
,例如Mapping
or TextSource
。
推荐阅读
- javascript - 与本地存储一起使用的挂钩调用无效
- wordpress - 将引导程序排入 WordPress 的最佳实践是什么?
- python - 散列numpy对象数组,hashlib如何查看对象的内容而不仅仅是指针?
- c++ - clang 在 macOS 中编译到哪个版本的 c++?
- sql - 比较日期和数据列
- java - 等待 JButton 被按下
- unix - 使用 txt 文件中列出的序列 ID(不带版本号)提取 FASTA 序列(带版本号)
- java - 如何从对象中只绑定一个字段?
- file-upload - 使用 Alfresco 共享表单页面,如何上传包含元数据的新文件?
- eclipse - IDE Eclipse 不链接到其他打开的项目,而是链接到它的 jar