通用协议上的Swift 4扩展函数,它将泛型函数作为参数

时间:2018-05-16 20:53:03

标签: swift generics

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扩展函数上指定哪些类型参数和约束?

1 个答案:

答案 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的具体实现替换,例如MappingTextSource或{{1}}。