Swift之泛型

写在前面:

泛型,类似于OC中的id类型,它可以指代任何一种类型,并不是在编译时确定其类型,而是在运行时确定其实际类型。使用泛型的函数,我们称之为泛型函数

intout关键字

现有两变量,要求其值互换

var someStr = "I am A"
var anotherStr = "I am B"

如果方法中参数得值在方法内部不会发生变化
即参数为常量,用let声明,let可省略

func swapTwoStrings1( a: String, b: String) {
    let tempA = b //对形参a的值不发生变化
    let tempB = a  //对形参b的值不发生变化
}
someStr  //"I am A"  对实参someStr的值不发生变化
anotherStr  //"I am B"  对实参anotherStr的值不发生变化

如果方法中的参数的值在方法内部会发生变化
参数需声明为变量,用var声明,var不可省略

func swapTwoStrings2(var a: String, var b: String) {
    let temporaryA = a
    a = b  //方法内a的值发生了改变
    b = temporaryA  //方法内b的值发生了改变
}
swapTwoStrings2(someStr, b: anotherStr)
someStr  //"I am A"   方法外someStr的值未改变
anotherStr   //"I am B"  方法外anotherStr的值未改变

如果想让传入的参数在进入方法后发生改变(参数在进入方法后值发生真正改变)
使用inout关键字(使形参和实参指向的内存一致)

func swapTwoStrings3(inout a: String, inout b: String) {
    let temporaryA = a
    a = b  //方法内a的值发生了改变
    b = temporaryA  //方法内b的值发生了改变
}

//传递参数时多出现了"&"符号,其实传递了字符串的地址
swapTwoStrings3(&someStr, b: &anotherStr)
someStr     //"I am B"   方法外someStr的值发生改变
anotherStr  //"I am A"  方法外anotherStr的值发生改变

注意:inout修饰的参数是不能有默认值的,有范围的参数集合也不能被修饰,另外,一个参数一旦被inout修饰,就不能再被var和let修饰了

泛型

上面的方法是为了把两个String变量的值相互交换
现要求把两个Int变量的值相互交换

func swapTwoInts(inout a: Int, inout b: Int){
    let temporaryA = a
    a = b
    b = temporaryA
}

从方法结构来看,swapTwoStrings3和swapTwoInts两个方法仅仅是参数类型不同,想办法合并他们

//T代表占位类型,可以是任何一种类型,
//a与b类型都是T,T只能是一种类型,所以a与b的类型一定要相同
func swapTwoValues<T>(inout a: T, inout b: T) {
    let temporaryA = a
    a = b
    b = temporaryA
}
swapTwoValues(&someStr, b: &anotherStr) //传入两个String类型
var someInt = 4
var anotherInt = 8
swapTwoValues(&someInt, b: &anotherInt)//传入两个Int类型
//swapTwoValues(&someStr, b: &anotherInt)  //报错a和b类型不同

使用多个泛型类型参数(在"<>"内用","分隔)

func toBeDict<KeyType,ValueType>(inout a: KeyType, inout b: ValueType) {
    Dictionary(dictionaryLiteral: (String(a), b))
}

toBeDict(&someStr,b: &someInt) //输出["I am A": 8]

泛型枚举
enum OptionalValue<T> {
case None
case Some(T)
}
var possibleInteger: OptionalValue<Int> = .None
possibleInteger = .Some(100)

用泛型来建立一个栈

//栈和Array相似,一个数组可以允许其里面任何位置的插入/删除操作,而栈,只允许在集合的末端添加新的项(如同push一个新值进栈)。同样的一个栈也只能从末端移除项(如同pop一个值出栈)
struct Stack<T> {
    //创建一个名为items的属性,使用空的T类型值数组对其进行初始化
    var items = [T]()
    //指定一个包含一个参数名为item的push方法,该参数必须是T类型
    mutating func push(item: T) {
        items.append(item)
    }
    //指定一个pop方法的返回值,该返回值将是一个T类型值
    mutating func pop() -> T {
        return items.removeLast()
    }
}

var stackOfStrings = Stack<String>() //一个String栈
stackOfStrings.push("uno")
stackOfStrings.push("dos")
stackOfStrings.pop()  //"dos"
stackOfStrings.pop()  //"uno"

泛型约束语法

第一种,泛型类型后面追加协议

//Equatable协议规定了T的类型一定能使用"=="和"!="
func findIndex<T: Equatable>(array: [T], valueToFind: T) -> Int? {
    
    for (index, value) in EnumerateSequence(array) {
        if value == valueToFind {
            return index
        }
    }
    return nil
}

findIndex([0,2,3,1], valueToFind: 1)

第二种,使用where约束

在实际使用where前,谈一下typealias(关联类型)

/*
typealias是一种常用于协议的特殊泛型,它可以使协议适用于更多情况
常规的写法应该是typealias MyInt = Int。表示给Int取一个别名为MyInt。
单独写typealias ItemType  代表给任意类型取别名为ItemType
协议中的关联类型的实际类型是不需要指定的,直到该协议接受。

注:这里的typealias不是用于约束泛型,而是为了下面的where约束泛型而服务的
*/
protocol Container {
    typealias ItemType
    //对象必须可以通过append方法添加一个新item到容器里;
    mutating func append(item: ItemType)
    //对象必须可以使用count属性获取容器里items的数量,并返回一个Int值
    var count: Int { get }  //get代表只读属性
    //对象必须可以通过容器的Int索引值下标可以检索到每一个item
    subscript(i: Int) -> ItemType { get }
}

//注意,这里满足Container约束的对象是StackPro结构体,而不是T
struct StackPro<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 {
        return items[i]
    }
}

var stackProOfStrings = StackPro<String>() //一个String栈
stackProOfStrings.push("uno")
stackProOfStrings.push("dos")
stackProOfStrings.count

扩展一个存在的类型为一指定关联类型(为了下面Array有ItemType这个属性)

//Array已经满足Container协议中的三个方法,其中的ItemType属性又是在运行时自动确定的类型,所以我们写一个空扩展就行了
extension Array: Container {}

//使用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
}

var stackProOfStrings2 = StackPro<String>()
stackProOfStrings2.push("uno")
stackProOfStrings2.push("dos")
stackProOfStrings2.push("tres")

var arrayOfStrings = ["uno", "dos", "tres"]

//按这么绕了一大圈之后arrayOfStrings和stackProOfStrings2这两个类型不同的对象可以比较了
if allItemsMatch(stackProOfStrings2, arrayOfStrings) {
    print("All items match.")  //输出 All items match
} else {
    print("Not all items match.")
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,367评论 6 512
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,959评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,750评论 0 357
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,226评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,252评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,975评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,592评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,497评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,027评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,147评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,274评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,953评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,623评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,143评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,260评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,607评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,271评论 2 358

推荐阅读更多精彩内容