首页 > 解决方案 > 通用协议上的 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为了满足编译器的要求,需要在扩展函数上指定哪些类型参数和约束?

标签: swiftgenerics

解决方案


您不能将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,例如Mappingor TextSource


推荐阅读