我想使用泛型类和类型约束:
class MyCustomClass<T : Equatable> {
var a: Array<T>
init() {
a = Array<T>()
}
}
工作正常。但是如果我想使用第二个协议,那将会发生什么,例如
class MyCustomClass<T : Equatable, IndexableBase> {
var a: Array<T>
init() {
a = Array<T>()
}
}
它表示初始化程序失败,因为我必须使用2而不是1个参数。我不明白。
答案 0 :(得分:17)
Swift 3
(我在您的示例中将IndexableBase
替换为Collection
,您应该更喜欢后者)
根据Swift 3,协议组合使用中缀运算符&
而不是之前的protocol<...>
结构,如接受和实现的进化提议中所述:
因此,使用协议组合,您可以将组合类型约束放在参数列表中的T
占位符中:
class MyCustomClass<T: Equatable & Collection> { /* ... */ }
作为协议组合的替代方法,您还可以使用where
子句来连接多个类型(和子类型)约束。根据已接受和实施的进化提案:
where
子句已移至声明的末尾,在这种情况下,您的示例将显示为:
class MyCustomClass<T: Equatable> where T: Comparable { /* ... */ }
或者,甚至将完整的协议组合与声明
末尾的where
子句放在一起
class MyCustomClass<T> where T: Equatable & Comparable { /* ... */ }
我们应该选择哪种风格?
有趣的讨论是我们应该考虑的“最佳实践”,因为这个特定主题没有指定Swift API指南。我们放置
考虑以下设计的示例,其中我们有一个构建协议,我们计划将其用作类型约束(Doable
),它本身包含associatedtype
我们可以放置一个类型约束
protocol Doable {
associatedtype U
}
使用上面的不同方法,以下三个选项都是有效的,语法
// alternative #1
func foo<T: Equatable & Doable>(_ bar: T) -> () where T.U: Comparable { /* ... */ }
// alternative #2
func foo<T: Equatable>(_ bar: T) -> () where T: Doable, T.U: Comparable { /* ... */ }
// alternative #3
func foo<T>(_ bar: T) -> () where T: Equatable & Doable, T.U: Comparable { /* ... */ }
我将引用来自the evolution thread that that brought forth SE-0081的Apple dev Joe Groff:
这是一个判断电话。这是我的感觉,在许多情况下,通用 参数受至少一个重要协议或基础的约束 这是值得提前调用的课程,所以允许这样做是合理的
之类的东西func foo<C: Collection>(x: C) -> C.Element
没有将
Collection
约束从前面拉得太远 声明。
因此,在上面的设计示例中,将协议组合用于直接应用于通用占位符T
的类型约束并将这些约束放在参数列表中,而{的子类型约束可能是合适的。 {1}}放在声明的末尾。即,上面的替代#1。
答案 1 :(得分:1)
您可以使用此解决方法
class MyCustomClass<T: Equatable where T: IndexableBase > {
var a: Array<T>
init() {
a = Array<T>()
}
}
斯威夫特4:
class MyCustomClass<T: Equatable> where T: Collection {
var a: Array<T>
init() {
a = Array<T>()
}
}