通用协议上的Swift 4扩展函数,以通用函数为参数

通用协议上的Swift 4扩展函数,以通用函数为参数,swift,generics,Swift,Generics,给定一个定义通用生产者(源)的简单协议: 以及能够在源类型之间转换的映射: protocol Source { associatedtype T func produce() -> T } 我可以用它来,例如,计数字符 struct TextSource : Source { private let text : String init(_ text: String) { self.text = text } func

给定一个定义通用生产者(源)的简单协议:

以及能够在源类型之间转换的映射:

protocol Source {
    associatedtype T

    func produce() -> T
}
我可以用它来,例如,计数字符

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
接近A

let t = TextSource("Hi!").map { (text: String) -> Int in
    return text.count
}
扩展源{
func映射(ublock:@escaping Mapping.Transformation)->Source{
返回映射(self,block)
}
}
被swift编译器拒绝的:

extension Source {
    func map<T, U : Source>(_ block: @escaping Mapping<T, U>.Transformation) -> Source {
        return Mapping(self, block)
    }
}
错误:函数签名中未使用泛型参数“U”
func映射(ublock:@escaping Mapping.Transformation)->Source{
^
方法B

error: generic parameter 'U' is not used in function signature
    func map<T, U : Source>(_ block: @escaping Mapping<T, U>.Transformation) -> Source {
                ^
扩展源{
func映射(ublock:@escaping Mapping.Transformation)->Source{
返回映射(self,block)
}
}
在这种情况下,编译器会抱怨缺少类型参数:

extension Source {
    func map<T>(_ block: @escaping Mapping<T, U>.Transformation) -> Source {
        return Mapping(self, block)
    }
}
错误:使用未声明的类型“U”
func映射(ublock:@escaping Mapping.Transformation)->Source{
^
问题


为了满足编译器的要求,需要在
map
扩展函数上指定哪些类型参数和约束?

您不能将
Source
用作
map
的具体返回类型,因为它是一个具有相关类型要求的协议

要解决此问题,可以使用
映射
函数返回
映射

扩展源{
func映射(u变换:@转义(T)->结果)->映射{
返回映射(自映射、转换)
}
}

该函数现在有一个
Self
需求。生成的
Mapping
类型有一个泛型类型参数
Self
,它被
Source
的具体实现所取代,例如
Mapping
TextSource

,非常感谢。这正是我在Swift 5.1中寻找的可以指定不透明的结果类型(即,
->某些源代码而不是
->映射
。您介意更新/扩展您的答案吗?请注意,不透明的返回类型有一些限制。如果您有
某些源代码
,您将丢失关联类型
T
的类型信息,因此您无法真正使用它。
TextSource(“嗨!”)例如.map{$0.count}.map{$0+42}
将不再编译,因为在第二个闭包中,不再可能知道
T
指的是什么。因此我认为
某些源代码
在这里不是一个好的解决方案。当Swift得到广义存在论时,可能会这样做。
error: generic parameter 'U' is not used in function signature
    func map<T, U : Source>(_ block: @escaping Mapping<T, U>.Transformation) -> Source {
                ^
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 {
                                              ^
extension Source {
    func map<Result>(_ transform: @escaping (T) -> Result) -> Mapping<Result, Self> {
        return Mapping(self, transform)
    }
}