swift泛型
2016-01-22 09:43
519 查看
/**
1.泛型所解决的问题
2.泛型函数
3.类型参数
4.命名类型参数
5.泛型类型
6.类型约束
7.关联类型
8.where语句
泛型代码可以让你写出根据自我需要定义、适用于任何类型的,灵活且可重用的函数和类型。可以避免重复的代码,用一种清晰和抽象方式来表达代码的意图
泛型是swift强大特征中的其中一个,许多swift标准库是通过泛型代码构建出来的。swift的数组和字典类型都是泛型集。可以创建一个Int数组,也可以创建一个String数组,或者甚至于可以是任何其他swift的类型数据数组。同样的,也可以创建存储任何指定类型的字典,而且这个类型可以是没有限制的
*/
//泛型所解决的问题
func swapTwoInts(inout a:
Int, inout b:
Int) {
let temporaryA = a;
a = b;
b = temporaryA;
}
var someInt = 3;
var anotherInt = 107;
swapTwoInts(&someInt, b: &anotherInt);
print(someInt,anotherInt);
/**
如果要交换其他类型的值,就需要创建更多相同的方法,只是参数类型不一样而已.
但实际应用中通常需要一个用处更强大并且尽可能的考虑到更多的灵活性单个函数,可以用来交换两个任何类型值,很幸运的是,泛型代码帮你解决了这种问题
在所有三个函数中,a和b的类型是一样的,如果a和b不是相同的类型,那他们两个就不能互换值。swift是类型安全的语言,所以它不允许一个String的变量和一个Double类型的变量互相交换值,如果一定要做就会报错
*/
func swapTwoStrings(inout a:
String, inout b:
String) {
let temporaryA = a;
a = b;
b = temporaryA;
}
func swapTwoDoubles(inout a:
Double, inout b:
Double) {
let temporaryA = a;
a = b;
b = temporaryA;
}
//泛型函数
/**
这个函数的泛型版本使用了占位类型名字(通常此情况下用字母T来表示)来代替实际类型名。占位类型名没有提示T必须是什么类型,但是它提示a和b必须是同一类型T,而不管T表示什么类型,只有swapTwoValues函数在每次调用时所传入的实际类型才能决定T所代表的类型
*/
func swapTwoValues<T>(inout a:
T, inout b:
T) {
let temporaryA = a;
a = b;
b = temporaryA;
}
var someInt2 = 4;
var anotherInt2 =
432;
swapTwoValues(&someInt2, b: &anotherInt2);
print(someInt2,
anotherInt2);
var someString = "123";
var anotherString =
"456";
swapTwoValues(&someString, b: &anotherString);
print("\(someString) ,
\(anotherString)");
//类型参数
/**
一旦一个类型参数被指定,那么其可以被使用来定义一个函数的参数类型,或作为一个函数返回类型,或用作函数主体中的注释类型。在这种情况下,被类型参数所代表的占位类型不管函数任何时候被调用,都会被实际类型所替换,你可支持多个类型参数,命名在尖括号中,用逗号分开
*/
//泛型类型
/**
通常在泛型函数中,swift允许定义自己的泛型类型。这些自定义类、结构体和枚举作用于任何类型
*/
struct IntStack {//Int型
var items = [Int]();
mutating func push(item:
Int) {
items.append(item);
}
mutating func pop() ->
Int {
return items.removeLast();
}
}
struct Stack<T> {//泛型
var items = [T]();
mutating func push(item:
T) {
items.append(item);
}
mutating func pop() ->
T {
return items.removeLast();
}
}
/**
T定义了一个名为“某种类型T”的节点提供给后来用。这种将来类型可以在结构体的定义里任何地方表示为'T'。在这种情况下,T在如下三个地方被用作节点:
1.创建一个名为items的属性,使用空的T类型值数组对其进行初始化
2.指定一个包含一个参数名为item的push方法,该参数必须是T类型
3.指定一个pop方法的返回值,该返回值将是一个T类型值
*/
var stackOfStrings =
Stack<String>();
stackOfStrings.push("uno");
print(stackOfStrings);
stackOfStrings.push("dos");
print(stackOfStrings);
stackOfStrings.push("tres");
print(stackOfStrings);
stackOfStrings.push("cuatro");
print(stackOfStrings);
let fromTheTop = stackOfStrings.pop();
print(stackOfStrings);
print(fromTheTop);
//类型约束
/**
详见资料
*/
//类型约束语法
/**
可以写一个在一个类型参数名后面的类型约束,通过冒号分隔,来作为类型参数链的一部分
func someFunction<T: SomeClass, U:SomeProtocol>(someT: T, someU: U) {
// function body goes here
}
第一个类型参数T,有一个需要T必须是SomeClass子类的类型约束;第二个类型参数U,有一个需要U必须遵循SomeProtocol协议的类型约束
*/
//类型约束行为
func findStringIndex(array: [String], valueToFind:
String) -> Int? {
for (index, value)
in array.enumerate() {
if value == valueToFind{
return index;
}
}
return
nil;
}
let strings = ["cat",
"dog", "llama",
"parakeet", "terrapin"];
if let foundIndex =
findStringIndex(strings, valueToFind:
"llama") {
print("The index of llama is
\(foundIndex)");
}
/**
Equatable协议,要求任何遵循的类型实现等式符(==)和不等符(!=)对任何两个该类型进行比较,所有的swift标准类型自动支持Equatable协议
*/
func findIndex<T:
Equatable>(array: [T], valueToFind:
T) -> Int? {
for (index, value)
in array.enumerate() {
if value == valueToFind{
return index;
}
}
return
nil;
}
let doubleIndex =
findIndex([3.213,234.2,12.33443,1.0], valueToFind:
234.2);
print(doubleIndex!);
//关联类型
/**
当定义一个协议时,有的时候声明一个或多个关联类型作为协议定义的一部分是非常有用的。一个关联类型给定作用于协议部分的类型一个节点(或别名)。作用于关联类型上实际类型是不需要指定的,直到该协议接受。关联类型被指定为typealias关键字
*/
//关联类型行为
/**
当定义一个协议时,有点时候声明一个或多个关联类型作为协议定义一部分是非常有用的。一个关联类型给定作用于协议部分的类型一个节点名(或别名)。作用于关联类型上实际类型是不需要指定的,直到该协议接受。关联类型被指定为typealias关键字
*/
protocol Container {
typealias ItemType;
mutating func append(item:
ItemType);
var count: Int {
get };
subscript(i: Int) ->
ItemType { get };
}
/**
Container协议定义了三个任何容器必须支持的兼容要求:
1.必须可能通过append方法添加一个新item到容器里
2.必须可能通过使用count属性获取容器里items的数量,并返回一个Int值
3.必须可能通过容器的Int索引值下标可以检索到每一个item
这个协议没有指定容器里Item是如何存储的或何种类型是允许的。这个协议只指定三个任何遵循Container类型所必须支持的功能点。一个遵循的类型也可以提供其他额外的功能,只要满足这三个条件
*/
struct IntStack2:
Container {
var items = [Int]();
mutating func push(item:Int) {
items.append(item);
}
mutating func pop() ->
Int {
return items.removeLast();
}
typealias ItemType =
Int;
mutating func append(item:
ItemType) {
self.push(item);
}
var count: Int {
return items.count;
}
subscript(i: Int) ->
Int {
return items[i];
}
}
//遵循Container协议的泛型类型
struct Stack2<T>:
Container {
var items = [T]();
mutating func push(item:
T) {
items.append(item);
}
mutating func pop() ->
T {
return items.removeLast();
}
mutating func append(item:
T) {
self.push(item);
}
var count: Int {
return items.count;
}
subscript(i:
Int) ->
T {//占位类型参数T被用作append方法的item参数和下标的返回类型。swift因此可以推断出被用作这个特定容器的ItemType的T的合适类型
return items[i];
}
}
//扩展一个存在的类型为一指定关联类型
extension Array:
Container {
// mutating func push(item: Element) {
// self.append(item);
// }
// mutating func pop() -> Element {
// self.removeLast();
// }
// mutating func append(item: Element) {
// self.push(item);
// }
// var count: Int {
// return self.count;
// }
// subscript(i: Int) -> Element {
// return self[i];
// }
}
//where语句
/**
类型约束确保你定义关联类型参数的需要和一泛型函数或类型有关联
对于关联类型的定义需求也是非常有用的,可以通过这样去定义where语句作为一个类型数队列的一部分。一个where语句使你能够要求一个关联类型遵循一个特定的协议,以及(或)那个特定的类型参数和关联类型可以是相同的。你可以写一个where语句,通过紧随放置where关键在类型参数队列后面,其后跟着一个或者多个针对关联类型的约束,以及(或)一个或多个类型和关联的等于关系
*/
func allItemsMatch<C1:
Container, C2: Container
where C1.ItemType ==
C2.ItemType,
C1.ItemType: Equatable>(someContainer:
C1, anotherContainer:
C2) -> Bool {
if someContainer.count != anotherContainer.count {
return
false;
}
for i in
0..<someContainer.count {
if someContainer[i] != anotherContainer[i]{
return
false;
}
}
return
true;
}
/**
这个函数用了两个参数:someContainer和anotherContainer。someContainer参数是类型C1,anotherContainer参数是类型C2。C1和C2是容器的两个占位类型参数,决定了这个函数何时被调用。
这个函数的类型参数列紧随在两个类型参数需求的后面
1.C1必须遵循Container协议,写作(C1: Container)
2.C2必须遵循Container协议
3.C1的ItemType同样是C2的ItemType (写作C1.ItemType
== C2.ItemType)
4.C1的ItemType必须遵循Equatable协议(写作C1.ItemType: Equatable)
第三个和第四个要求被定义为一个where语句的一部分,写在关键字where后面,作为函数类型参数链的一部分
*/
var stackOfStrings2 =
Stack2<String>();
stackOfStrings.push("uno");
stackOfStrings.push("dos");
stackOfStrings.push("tres");
var arrayOfStrings = ["uno",
"dos", "tres"];
if allItemsMatch(stackOfStrings2, anotherContainer:
arrayOfStrings) {
print("All items match");
}else {
print("Not all items match");
}
1.泛型所解决的问题
2.泛型函数
3.类型参数
4.命名类型参数
5.泛型类型
6.类型约束
7.关联类型
8.where语句
泛型代码可以让你写出根据自我需要定义、适用于任何类型的,灵活且可重用的函数和类型。可以避免重复的代码,用一种清晰和抽象方式来表达代码的意图
泛型是swift强大特征中的其中一个,许多swift标准库是通过泛型代码构建出来的。swift的数组和字典类型都是泛型集。可以创建一个Int数组,也可以创建一个String数组,或者甚至于可以是任何其他swift的类型数据数组。同样的,也可以创建存储任何指定类型的字典,而且这个类型可以是没有限制的
*/
//泛型所解决的问题
func swapTwoInts(inout a:
Int, inout b:
Int) {
let temporaryA = a;
a = b;
b = temporaryA;
}
var someInt = 3;
var anotherInt = 107;
swapTwoInts(&someInt, b: &anotherInt);
print(someInt,anotherInt);
/**
如果要交换其他类型的值,就需要创建更多相同的方法,只是参数类型不一样而已.
但实际应用中通常需要一个用处更强大并且尽可能的考虑到更多的灵活性单个函数,可以用来交换两个任何类型值,很幸运的是,泛型代码帮你解决了这种问题
在所有三个函数中,a和b的类型是一样的,如果a和b不是相同的类型,那他们两个就不能互换值。swift是类型安全的语言,所以它不允许一个String的变量和一个Double类型的变量互相交换值,如果一定要做就会报错
*/
func swapTwoStrings(inout a:
String, inout b:
String) {
let temporaryA = a;
a = b;
b = temporaryA;
}
func swapTwoDoubles(inout a:
Double, inout b:
Double) {
let temporaryA = a;
a = b;
b = temporaryA;
}
//泛型函数
/**
这个函数的泛型版本使用了占位类型名字(通常此情况下用字母T来表示)来代替实际类型名。占位类型名没有提示T必须是什么类型,但是它提示a和b必须是同一类型T,而不管T表示什么类型,只有swapTwoValues函数在每次调用时所传入的实际类型才能决定T所代表的类型
*/
func swapTwoValues<T>(inout a:
T, inout b:
T) {
let temporaryA = a;
a = b;
b = temporaryA;
}
var someInt2 = 4;
var anotherInt2 =
432;
swapTwoValues(&someInt2, b: &anotherInt2);
print(someInt2,
anotherInt2);
var someString = "123";
var anotherString =
"456";
swapTwoValues(&someString, b: &anotherString);
print("\(someString) ,
\(anotherString)");
//类型参数
/**
一旦一个类型参数被指定,那么其可以被使用来定义一个函数的参数类型,或作为一个函数返回类型,或用作函数主体中的注释类型。在这种情况下,被类型参数所代表的占位类型不管函数任何时候被调用,都会被实际类型所替换,你可支持多个类型参数,命名在尖括号中,用逗号分开
*/
//泛型类型
/**
通常在泛型函数中,swift允许定义自己的泛型类型。这些自定义类、结构体和枚举作用于任何类型
*/
struct IntStack {//Int型
var items = [Int]();
mutating func push(item:
Int) {
items.append(item);
}
mutating func pop() ->
Int {
return items.removeLast();
}
}
struct Stack<T> {//泛型
var items = [T]();
mutating func push(item:
T) {
items.append(item);
}
mutating func pop() ->
T {
return items.removeLast();
}
}
/**
T定义了一个名为“某种类型T”的节点提供给后来用。这种将来类型可以在结构体的定义里任何地方表示为'T'。在这种情况下,T在如下三个地方被用作节点:
1.创建一个名为items的属性,使用空的T类型值数组对其进行初始化
2.指定一个包含一个参数名为item的push方法,该参数必须是T类型
3.指定一个pop方法的返回值,该返回值将是一个T类型值
*/
var stackOfStrings =
Stack<String>();
stackOfStrings.push("uno");
print(stackOfStrings);
stackOfStrings.push("dos");
print(stackOfStrings);
stackOfStrings.push("tres");
print(stackOfStrings);
stackOfStrings.push("cuatro");
print(stackOfStrings);
let fromTheTop = stackOfStrings.pop();
print(stackOfStrings);
print(fromTheTop);
//类型约束
/**
详见资料
*/
//类型约束语法
/**
可以写一个在一个类型参数名后面的类型约束,通过冒号分隔,来作为类型参数链的一部分
func someFunction<T: SomeClass, U:SomeProtocol>(someT: T, someU: U) {
// function body goes here
}
第一个类型参数T,有一个需要T必须是SomeClass子类的类型约束;第二个类型参数U,有一个需要U必须遵循SomeProtocol协议的类型约束
*/
//类型约束行为
func findStringIndex(array: [String], valueToFind:
String) -> Int? {
for (index, value)
in array.enumerate() {
if value == valueToFind{
return index;
}
}
return
nil;
}
let strings = ["cat",
"dog", "llama",
"parakeet", "terrapin"];
if let foundIndex =
findStringIndex(strings, valueToFind:
"llama") {
print("The index of llama is
\(foundIndex)");
}
/**
Equatable协议,要求任何遵循的类型实现等式符(==)和不等符(!=)对任何两个该类型进行比较,所有的swift标准类型自动支持Equatable协议
*/
func findIndex<T:
Equatable>(array: [T], valueToFind:
T) -> Int? {
for (index, value)
in array.enumerate() {
if value == valueToFind{
return index;
}
}
return
nil;
}
let doubleIndex =
findIndex([3.213,234.2,12.33443,1.0], valueToFind:
234.2);
print(doubleIndex!);
//关联类型
/**
当定义一个协议时,有的时候声明一个或多个关联类型作为协议定义的一部分是非常有用的。一个关联类型给定作用于协议部分的类型一个节点(或别名)。作用于关联类型上实际类型是不需要指定的,直到该协议接受。关联类型被指定为typealias关键字
*/
//关联类型行为
/**
当定义一个协议时,有点时候声明一个或多个关联类型作为协议定义一部分是非常有用的。一个关联类型给定作用于协议部分的类型一个节点名(或别名)。作用于关联类型上实际类型是不需要指定的,直到该协议接受。关联类型被指定为typealias关键字
*/
protocol Container {
typealias ItemType;
mutating func append(item:
ItemType);
var count: Int {
get };
subscript(i: Int) ->
ItemType { get };
}
/**
Container协议定义了三个任何容器必须支持的兼容要求:
1.必须可能通过append方法添加一个新item到容器里
2.必须可能通过使用count属性获取容器里items的数量,并返回一个Int值
3.必须可能通过容器的Int索引值下标可以检索到每一个item
这个协议没有指定容器里Item是如何存储的或何种类型是允许的。这个协议只指定三个任何遵循Container类型所必须支持的功能点。一个遵循的类型也可以提供其他额外的功能,只要满足这三个条件
*/
struct IntStack2:
Container {
var items = [Int]();
mutating func push(item:Int) {
items.append(item);
}
mutating func pop() ->
Int {
return items.removeLast();
}
typealias ItemType =
Int;
mutating func append(item:
ItemType) {
self.push(item);
}
var count: Int {
return items.count;
}
subscript(i: Int) ->
Int {
return items[i];
}
}
//遵循Container协议的泛型类型
struct Stack2<T>:
Container {
var items = [T]();
mutating func push(item:
T) {
items.append(item);
}
mutating func pop() ->
T {
return items.removeLast();
}
mutating func append(item:
T) {
self.push(item);
}
var count: Int {
return items.count;
}
subscript(i:
Int) ->
T {//占位类型参数T被用作append方法的item参数和下标的返回类型。swift因此可以推断出被用作这个特定容器的ItemType的T的合适类型
return items[i];
}
}
//扩展一个存在的类型为一指定关联类型
extension Array:
Container {
// mutating func push(item: Element) {
// self.append(item);
// }
// mutating func pop() -> Element {
// self.removeLast();
// }
// mutating func append(item: Element) {
// self.push(item);
// }
// var count: Int {
// return self.count;
// }
// subscript(i: Int) -> Element {
// return self[i];
// }
}
//where语句
/**
类型约束确保你定义关联类型参数的需要和一泛型函数或类型有关联
对于关联类型的定义需求也是非常有用的,可以通过这样去定义where语句作为一个类型数队列的一部分。一个where语句使你能够要求一个关联类型遵循一个特定的协议,以及(或)那个特定的类型参数和关联类型可以是相同的。你可以写一个where语句,通过紧随放置where关键在类型参数队列后面,其后跟着一个或者多个针对关联类型的约束,以及(或)一个或多个类型和关联的等于关系
*/
func allItemsMatch<C1:
Container, C2: Container
where C1.ItemType ==
C2.ItemType,
C1.ItemType: Equatable>(someContainer:
C1, anotherContainer:
C2) -> Bool {
if someContainer.count != anotherContainer.count {
return
false;
}
for i in
0..<someContainer.count {
if someContainer[i] != anotherContainer[i]{
return
false;
}
}
return
true;
}
/**
这个函数用了两个参数:someContainer和anotherContainer。someContainer参数是类型C1,anotherContainer参数是类型C2。C1和C2是容器的两个占位类型参数,决定了这个函数何时被调用。
这个函数的类型参数列紧随在两个类型参数需求的后面
1.C1必须遵循Container协议,写作(C1: Container)
2.C2必须遵循Container协议
3.C1的ItemType同样是C2的ItemType (写作C1.ItemType
== C2.ItemType)
4.C1的ItemType必须遵循Equatable协议(写作C1.ItemType: Equatable)
第三个和第四个要求被定义为一个where语句的一部分,写在关键字where后面,作为函数类型参数链的一部分
*/
var stackOfStrings2 =
Stack2<String>();
stackOfStrings.push("uno");
stackOfStrings.push("dos");
stackOfStrings.push("tres");
var arrayOfStrings = ["uno",
"dos", "tres"];
if allItemsMatch(stackOfStrings2, anotherContainer:
arrayOfStrings) {
print("All items match");
}else {
print("Not all items match");
}
相关文章推荐
- swift协议
- swift类型扩展
- swift类型嵌套
- swift类型检查
- swift可选链
- swift自动引用计数
- swift析构过程
- swift构造过程
- swift继承
- 【iOS】swift-如何理解 if let 与guard?
- 【iOS】swift-如何理解 if let 与guard?
- swift学习笔记之-类和结构体
- LeetCode 2. Add Two Numbers swift
- LeetCode 01 Two Sum swift
- Swift 使用代理和闭包(closure)反向传值
- OC和Swift中的static
- OC和Swift中的static
- Swift Control Flow控制流
- swift论坛正式上线
- swift2.0 UIImagePickerController 拍照 相册 录像