24.11. 包含上下文关系的 where 分句

当你使用泛型时,可以为没有独立类型约束的声明添加 where 分句。例如,你可以使用 where 分句为泛型添加下标,或为扩展方法添加泛型约束。Container 结构体是个泛型,下面的例子通过 where 分句让新的方法声明其调用所需要满足的类型约束。

extension Container {
    func average() -> Double where Item == Int {
        var sum = 0.0
        for index in 0..<count {
            sum += Double(self[index])
        }
        return sum / Double(count)
    }
    func endsWith(_ item: Item) -> Bool where Item: Equatable {
        return count >= 1 && self[count-1] == item
    }
}
let numbers = [1260, 1200, 98, 37]
print(numbers.average())
// 输出 "648.75"
print(numbers.endsWith(37))
// 输出 "true"

例子中,当 Item 是整型时为 Container 添加 average() 方法,当 Item 遵循 Equatable 时添加 endsWith(_:) 方法。两个方法都通过 where 分句对 Container 中定义的泛型 Item 进行了约束。

如果不使用包含上下文关系的 where 分句,需要写两个扩展,并为每个扩展分别加上 where 分句。下面的例子和上面的具有相同效果。

extension Container where Item == Int {
    func average() -> Double {
        var sum = 0.0
        for index in 0..<count {
            sum += Double(self[index])
        }
        return sum / Double(count)
    }
}
extension Container where Item: Equatable {
    func endsWith(_ item: Item) -> Bool {
        return count >= 1 && self[count-1] == item
    }
}

在包含上下文关系的 where 分句的例子中,由于每个方法的 where 分句各自声明了需要满足的条件,因此 average()endsWith(_:) 的实现能放在同一个扩展里。而将 where 分句放在扩展进行声明也能起到同样的效果,但每一个扩展只能有一个必备条件。