我已经定义了两个通用函数
func job<T: Comparable>(x: T) {
println("1")
}
func job<T: Hashable>(x: T) {
println("2")
}
当我尝试拨打其中一个时,例如:
let myInt: Int = 1 // Explicit Int just for clarity of the example
job(myInt)
当然,斯威夫特抱怨并抛出错误
模糊地使用&#39;
这是可以理解的,因为我不清楚是否要使用可比较或 Hashable ( Int 符合这两者)
有没有办法可以提示我想要使用哪个编译器?
答案 0 :(得分:11)
这是不明确的,因为Int
同时是Hashable
和Comparable
,并且这两个协议都不在同一层次结构中。 (您可以查看Int
protocol 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
// ...
}
在此示例中,generator属性可以是符合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'
相反,我们需要使用t
关键字将(upcast?)as
转换为特定协议,并以这种方式调用特定的泛型函数:
p(t as Printable)
// Printable: true
p(t as BooleanType)
// BooleanType: true
因此,只要我们有一个合格的协议,我们就可以选择要调用的泛型方法的哪个版本。