这是模棱两可的,因为Int 既是Hashable 又是Comparable,而且这两个协议都不属于同一个层次结构。 (可以查看Intprotocol hierarchy on Swifter。)
func f<T: Hashable>(t: T) {
println("Hashable: \(t)")
}
func f<T: Comparable>(t: T) {
println("Comparable: \(t)")
}
let number = 5
f(number)
// error: ambiguous use of 'f'
由于每个协议的相关类型要求,您无法明确告诉它要调用哪个函数,但您可以做的是定义第三个函数:
func f<T: Comparable where T: Hashable>(t: T) {
println("Both Hashable & Comparable: \(t)")
}
f(number)
// Both Hashable & Comparable: 5
这就是Swift implements ..< 运算符的方式,否则对于同时实现Comparable 和ForwardIndexType 的类型来说,这将是模棱两可的。
为了进一步扩展,这里看看我的意思是“你不能明确地告诉它调用哪个函数,因为每个协议都有相关的类型要求。”协议可以用作类型,如 Swift 书籍chapter on Protocols 中所述:
protocol RandomNumberGenerator {
func random() -> Double
}
class Dice {
let generator: RandomNumberGenerator
// ...
}
在此示例中,生成器属性可以是符合 RandomNumberGenerator 的任何类型 - 类似于在 Objective-C 中使用 id<ProtocolName> 的方式。但是,协议只能在其声明中不包含关联类型或引用 Self 时用作类型。不幸的是,这几乎排除了 Swift 中的所有内置类型,包括 Hashable 和 Comparable。
Hashable继承自Equatable,在定义==运算符时引用Self:
func ==(lhs: Self, rhs: Self) -> Bool
而Comparable 对其运算符也是如此:
func <=(lhs: Self, rhs: Self) -> Bool
// similar definitions for <, >, and >=
这些协议只能用作通用约束,在声明变量时不能用作类型。 (据我所知,这是未记录的,但可以通过错误消息发现。)
两个没有限制的协议是Printable 和BooleanType,所以我们可以看看它们是如何工作的。 Bool 是唯一符合BooleanType 的内置类型,它也是Printable,所以这将是我们的测试类型。这是我们的通用函数p() 和变量t - 请注意,和以前一样,我们不能只用t 调用函数:
func p<T: Printable>(t: T) {
println("Printable: \(t)")
}
func p<T: BooleanType>(t: T) {
println("BooleanType: \(t)")
}
let t: Bool = true
p(t)
// error: Ambiguous use of 'p'
相反,我们需要使用 as 关键字将t 强制转换(向上转换?)到特定协议,并以这种方式调用特定的通用函数:
p(t as Printable)
// Printable: true
p(t as BooleanType)
// BooleanType: true
所以只要我们有一个合格的协议,我们就可以选择调用泛型方法的哪个变体。