其实真的觉得即使自己能独立完成项目,还有是太多太多学习的地方可以不断提高,毕竟如果重复写一些代码是没有意义的.虽然说我已经使用了swift写了一个项目并且已经在AppStore里面发布,但是对于swift的认识还是很浅薄的.最近在重新看swift programming language一书,重新看了一遍里面的内容--其实对于泛型,我最初的理解是来源于Java,在项目中我真的比较少用到泛型.
泛型需求的产生
下面是书里面的代码:
func swapTwoInt(inout a:Int,inout b:Int){
let tempA = a;
a = b;
b = tempA
}
要是我有这个交换两个内容的要求,但是这紧紧单纯是对Int但种类型的配置,如果我还需要有String和Double的话,我必须要拷贝代码:
func swapTwoString(inout a:String,inout b:String){
let tempA = a;
a = b;
b = tempA
}
func swapTwoDouble(inout a:Double,inout b:Double){
let tempA = a;
a = b;
b = tempA
}
于是我们产生了泛型,它可以定义一种统一的类型<T>,这个时候你可以在参数里面写入这个参数,它代表了前后一致的类型,如String,Int,Double...
func swapTwoValues<T>(inout a: T, inout _ b: T){
let tempA = a;
a = b;
b = tempA
}
在我写泛型的时候,遇到的第一个问题是返回值怎么处理?
唔哼,这个问题让我们继续把泛型的其他定义看下去的时候再继续思考吧.
命名类型参数
那么,泛型的书写方法就是用一对箭括号把类型名称合并起来:如 <T>,当然,你也可以一两个其他字母表示,<U,T>
泛型类型
其中,书中里面举了一个泛型类型的例子是这样的:
struct IntStack {
var items = [Int]();
/*
mutating关键字:由于swift功能强大,不仅可以让class遵守,也可以让enum和struct遵守
mutating关键字在定义协议的方法的时候可以在前面加上,让其三种类型在遵守协议的时候对有关键字的方法有不同的"提示":
class: 在class中实现带有mutating方法的接口时,不用mutating进行修饰。因为对于class来说,类的成员变量和方法都是透明的,所以不必使用 mutating 来进行修饰
enum:
struct:如果将struct中的mutating去掉,则会报错不能改变结构体的成员。
*/
//将一个数值入栈
mutating func push(item:Int)
{
items.append(item)
}
//和内存中的栈一样,先进后出,所以只要移除最后一个元素即可
mutating func pop() -> Int{
return items.removeLast()
}
}
但是只针对Int一种类型避免也显得太弱了吧,所以我们可以用泛型对其进行改良:
struct Stack<T> {
var items = [T]()
mutating func push(item: T) {
items.append(item)
}
mutating func pop() -> T {
return items.removeLast()
}
}
使用的时候可以将该类型延伸为相应的类型,如string:
var stringsInStack = Stack<String>()
stringsInStack.push("1");//1
stringsInStack.push("2");//1,2
stringsInStack.push("3");//1,2,3
stringsInStack.push("4");//1,2,3,4
stringsInStack.pop()//1,2,3
现在,有点明白了Array和Dictionary为什么可以指定类型了吧,其实无形中我们已经用了很多泛型的内容,只是我们缺少了总结和理解:
//定义了一个内容必须为字符串的数组
var arr :[String] = []
arr[0] = "name";
arr[1] = "age";
arr[3] = "height";
//定义了一个key为String,value为AnyObject的字典
var parma : [String:AnyObject] = [:]
parma["name"] = "shiron"
parma["age"] = 22
parma["height"] = 1.70
这里可以延伸出后面的一个话题:类型约束.
类型约束
输入Dictionary点进去可以看到该类的属性和方法:
public struct Dictionary<Key : Hashable, Value> : CollectionType, DictionaryLiteralConvertible{
各种dict的属性和方法......
}
我们发现在dict对泛型进行定义的时候,key有一个特殊的限制:
****<key: hashable,Value>****
此时,我们可以看到key被强制遵守了一个hashable的协议(注意:Swift 标准库中定义的一个特定协议,所有的 Swift 基本类型(如 String , Int , Double 和 Bool )默认都是可哈希。)
当你对泛型的有较高的输入要求时,可以限制某种类或者协议来进行类型约束,定义方法就是在泛型字母后面添加 T:SomeProtocol或者U:someClass
func someFunction<T:someClass,U:someProtocol>(someT:T,someU:U){
//函数主体
}
扩展一个泛型类型
当然我们泛型的好用之处不仅这么一点点.
书中还对Stack的类型作出了一个扩展:
extension Stack {
var topItem: T? {
return items.isEmpty ? nil : items[items.count - 1]
}
}
topItem 属性会返回一个 T 类型的可选值。当栈为空的时候, topItem 将会返回 nil ;当栈不为空的时候, topItem 会返回 items 数组中的最后一个元素,然而你注意到了吗?我们在扩展里面并没有使用泛型类型的定义,它是从结构体中直接带过来了,对它进行解包则可以自己使用:
if let topItem = stackOfStrings.topItem {
print(" \(topItem)")
}