- 泛型函数定义
- 泛型函数可以用于任何类型。
- 类型形式参数
- 上面swapTwoValues(_:_:)中,占位符类型T就是一个类型形式参数的例子。类型形式参数指定并且命名一个占位符类型,紧挨着写在函数名后面的一对尖括号(比如<T>)。
- 一旦你指定了一个类型形式参数,你就可以用它定义一个函数形式参数(比如)swapTwoValues(_:_:)函数总的形式参数a和b)的类型,或者用它做函数返回值类型,或者做函数数体中类型标注。在不同情况下,用调用函数的时实际类型来替换类型形式参数。(上面的swapTwoValues(_:_:)例子中,第一次调用函数的时候Int替换了T,第二次调用时String替换的。)。
- 你可以通过在尖括号里写多个逗号隔开的类型形式参数名,来提供更多类型形式参数。
- 命名类型形式参数
- 大多数情况下,类型形式参数的名字要有描述性,比如Dictionary<key,value>中的key和value,借此告知读者类型形式和泛型类型、泛型用到的函数之间的关系。但是,他们之间的关系没有意义时,一般按惯例用单个字母命名,比如T、U、V,比如上面swapTwoValues(_:_:)函数中的T。
- 类型形式参数永远用大写开头的驼峰命名法(比如T和MyTypeParameter)命名以指明它们是一个类型的占位符,不是一个值。
- 泛型类型
- 除了泛型函数,swift允许你自定义自己的泛型类型。它们可以用于任意类型的自定义类、结构体、枚举、和array、dictionary方式类似。
- 扩展泛型类型
- 当你扩展一个泛型类型时,不需要在扩展的定义中提供类型形式列表。原始类型定义的类型形式参数列表在扩展体里仍然有效,并且原始类型形式参数列表名称也用于扩展类型形式参数。
- 【代码演示】
func swapTwoValues<T>(_ a: inout T,_ b:inout T){
let temporaryA = a
a = b
b = temporaryA
}
- 类型约束
- swapTwoValues(_:_:)函数和Stack类型可以用于任意类型。但是,有时在用于泛型类型上,强制其遵循特定的类型约束很有用。类型约束指出一个类型形式参数必须继承自特定类,或者遵循特停的协议、组合协议。
- 例如,swift的D actionary类型在可以用于字典中键的类型上设置了一个限制。如字典中描述的一样,字典键的类型必须是可哈希的。也就是说,它必须提供一种使其可以唯一表示的方法。dictionary需要它的键是可哈希的,以便它可以检查字典中是否包含一个特定的值。没有了这个要求,dictionary不能区分该插入还是替换一个指定键的值,也不能在字典中查找已经给定键的值。
- 类型约束语法
- 在一个类型形式参数名称后面放置一个类或者作为形式参数列表的一部分,并用冒号隔开,以写出一个类型约束。下面展示了一个泛型函数的类型约束的基本语法(和泛型的语法相同)。
- 类型约束的应用
- 这是一个叫做findIndex(ofString:in:)的非泛型函数,在给定的string值数组中查找给定string值。findIndex(ofString:in:)函数返回一个可选的int值,如果找到了给定字符串,它会返回数组中第一个匹配的字符串的索引值,如果找不到给定字符串就返回nil.
- swift标准库中定义了一个叫做Equatabled的协议,要求遵循其协议的类型要实现相等操作符(==)和不等操作符(!=),用于比较该类型的任意两个值。所有swift标准库中类型自动支持Equatabled协议。
- 任何Equatabled的类型都能安全得用于findIndex(of:in:)函数,因为可以保证那些类型支持相等操作符。为了表达这个事实,当你定义函数时将Equatabled类型约束作为类型形式参数定义的一部分书写。
【代码演示】
func findIndex(ofString valueToFind:String,in array:[String]) -> Int?{
for (index,value) in array.enumerated() {
if value == valueToFind{
return index
}
}
return nil
}
func subFindIndex<T:Equatable>(of valueToFind:T,in array:[T]) -> Int?{
for (index,value) in array.enumerated() {
if value == valueToFind{
return index
}
}
return nil
}
- 关联类型
- 定义一个协议时,有时在协议定义里声明一个或多个关联类型时很有用的。关联类型给协议中用到的类型一个占位符名称。直到采纳协议时,才能指定用于该关联类型的实际类型。关联类型通过associated type关键字指定。
- 关联类型的应用
- 看事例代码。
- 关联类型的约束
- 你可以在协议里给关联类型添加约束要求遵循的类型满足约束。
- 在关联类型约束里使用协议
- 协议可以作为它自身的要求出现。
- where 子句
- 如类型约束中描述的一样,类型约束允许你在泛型函数或泛型类型相关的类型形式参数上定义要求。
- 类型约束在为关联类型定义要求时也很有用。通过定义一个泛型where子句来实现。泛型where子句让你能够要求一个关联类型必须遵循指定的协议,或者通过指定的类型形式参数和关联类型必须相同。泛型where子句以where关键字开头,后接关联类型的约束和关联类型一致的关系。泛型where子句写在一个类型或函数体的左半个大括号前面。
- 带有泛型where子句的扩展
- 你同时可以使用泛型的where子句来作为扩展的一部分。
- 关联类型的泛型where子句
- 你可以在关联类型中包含一个泛型where子句。
- 泛型下标
- 下标可以是泛型,他们可以包含泛型where分句。你可以在subscript后面用尖括号写类型占位符,你还可以在下标代码块花括号前面写泛型where分句。
- 【代码演示】
//3、关联类型的约束 protocol Container{ associatedtype Item:Equatable mutating func append(_ iteam:Item) var count:Int {get} subscript(i:Int) -> Item{get} } protocol SuffixableContainer:Container{ associatedtype Suffix:SuffixableContainer where Suffix.Item == Item func suffix(_ size:Int) ->Suffix } struct IntStack:Container { var items = [Int]() mutating func append(_ iteam: Int) { items.append(iteam) } var count:Int{ return items.count } subscript(i: Int) -> Int { return items[i] } } //4、关联类型的泛型where子句 protocol Country { associatedtype Item mutating func append(_ item:Item) var count:Int{get} subscript(i:Int) -> Item {get} associatedtype Iterator:IteratorProtocol where Iterator.Element == Item func makeIterator () -> Iterator } protocol nextCountry:Country where Item:Comparable{} //5、泛型下标 extension Container { subscript<Indirect:Sequence>(indices:Indirect) ->[Item] where Indirect.Iterator.Element == Int{ var result = [Item]() for index in indices{ result.append(self[index]) } return result } }