Swift 4泛型数组作为泛型类中的参数

时间:2017-10-03 08:38:46

标签: ios swift generics xctest swift4

我有一个在测试中使用的匹配器

class GWMatcher<ResultType> {
    let result: ResultType
    let message: String

    init(result: ResultType, message: String) {
        self.result = result
        self.message = message
    }
}

我想添加扩展以将其用于数组。我希望它像这样:

extension GWMatcher where ResultType == [Equatable] {
    func checkEqual(_ expression: ResultType) {
        XCTAssertEqual(self.result, expression, self.message)
    }
}

但是编译器说:

  

无法使用XCTAssertEqual类型的参数列表调用([Equatable], Array<Equatable>, String)

有没有人有想法,是否可以做这样的事情?

1 个答案:

答案 0 :(得分:1)

我相信你正在遇到Swift类型系统的边缘情况。特别是,通用约束:

extension GWMatcher where ResultType == [Equatable]

应该真正指定为:

extension GWMatcher where ResultType == [T] where T: Equatable

但目前不支持最后一种形式(扩展程序)。这很重要,因为Swift协议符合自身,这需要对[Equatable]按预期工作为真(这就是为什么需要具体类型T)。我知道,因为地狱很棘手......;)

此外,标准Equatable协议只能用作通用约束,因为它具有Self要求(使用关联类型的协议也表现相似)。这种斯威夫特的限制也可能归咎于此。

解决方法即可。无论如何,作为 less 类型安全的解决方法,请尝试这样做:

extension GWMatcher {
    func checkEqual<T: Equatable>(_ expression: [T]) {
        guard let result = self.result as? [T] else {
            XCTFail("Expected type \([T].self)")
            return
        }
        XCTAssertEqual(result, expression)
    }
}

这不是原始设计的类型安全,因为它可以在所有 GWMatcher类型上使用,包括那些ResultType不是&#39;输入为[Equatable]。不过,它应该按预期工作。