swift泛型函數(shù)

本文轉(zhuǎn)載自http://blog.csdn.net/youshaoduo/article/details/54863470

泛型能夠讓開發(fā)者編寫自定義需求已經(jīng)任意類型的靈活可用的的函數(shù)和類型。能夠讓我們避免重復(fù)的代碼。用一種清晰和抽象的方式來表達(dá)代碼的意圖。

1.泛型解決的問題

下面是一個(gè)非泛型的例子

[objc]view plaincopy

func?swapTwoIntValue(a:?inout?Int,b:?inout?Int){

let?tempValue?=?a

a?=?b

b?=?tempValue

}

這個(gè)函數(shù)用來交換兩個(gè)整形的數(shù)值

[objc]view plaincopy

var?a?=1

var?b?=2

swapTwoIntValue(a:?&a,b:?&b)

print(a,?b)//2,1

對(duì)于這個(gè)例子,假如我們想交換兩個(gè)Double類型、或者是其他類型的值,就需要針對(duì)每個(gè)類型寫不同的方法,只是參數(shù)類型不同。為了解決這個(gè)問題,Swift提供了泛型,幫助我們來解決這個(gè)問題。

注意:Swift是安全的語言,不允許兩個(gè)不同類型互換值

2.泛型函數(shù)

下面是一個(gè)泛型的函數(shù)

[objc]view plaincopy

func?swapTwoValue(a:?inout?T,b:?inout?T){

let?tempValue?=?a

a?=?b

b?=?tempValue

}

這個(gè)函數(shù)主體、功能跟上面的例子類似,用來交換兩個(gè)同樣類型的值,但是這個(gè)函數(shù)用 T 占位符來代替實(shí)際的類型。并沒有指定具體的類型,但是傳入的a ,b 必須是同一類型T。在調(diào)用這個(gè)函數(shù)的時(shí)候才能指定 T 是那種具體的類型。還有函數(shù)名后跟的那個(gè) 是函數(shù)定義的一個(gè)占位類型名,并不會(huì)查找T的具體類型

[objc]view plaincopy

swapTwoValue(&oneInt,b:?&twoInt)

print("oneInt:\(oneInt),twoInt:\(twoInt)")//?oneInt:3,twoInt:4

var?oneStr?="hello"

var?twoStr?="world"

swapTwoValue(&oneStr,b:?&twoStr)

print("oneStr:\(oneStr),twoStr:\(twoStr)")//?oneStr:world,twoStr:hello

var?oneDouble?=10.01

var?twoDouble?=20.02

swapTwoValue(&oneDouble,b:?&twoDouble)

print("oneDouble:\(oneDouble),twoDouble:\(twoDouble)")//?oneDouble:20.02,twoDouble:10.01

這個(gè)例子用泛型完美的解決了上述的問題,只需要定義一個(gè)泛型函數(shù),只要保證 傳入的兩個(gè)參數(shù)是同一個(gè)類型,就不用根據(jù)傳入?yún)?shù)的類型不同而寫不同的方法。

3.類型參數(shù)

在上面的泛型函數(shù)例子中,占位符T是類型參數(shù)的一個(gè)例子。類型參數(shù)指定并命名一個(gè)占位符類型,并用<>包裹,放在函數(shù)名后面。一旦一個(gè)參數(shù)類型確定,就可以指定參數(shù)類型,或者返回值的類型,還可以用作函數(shù)體的注釋類型。在調(diào)用的時(shí)候會(huì)被實(shí)際的類型替代,如傳遞的是Int,就替換為Int,如果傳入的是Double類型就替換為Double等等

4.命名類型參數(shù)

上面的泛型例子的 T,只是一個(gè)描述性的名字,通常用單一的字母來命名,例如:T、U、V等。T代表只是一個(gè)占位符,命名規(guī)則同駝峰命名法

5.泛型類型

除了定義泛型函數(shù),還可以定義泛型類型。如Array,Dictionary的用法

下面展示一個(gè)非泛型版本棧

[objc]view plaincopy

structIntStack?{

var?items?=?[Int]()

mutating?func?push(item:?Int)?{

items.append(item)

}

mutating?func?pop(item:?Int)?->?Int?{

returnitems.removeLast()

}

}

這個(gè)是一個(gè)泛型版本的棧

[objc]view plaincopy

structStack?{

var?items?=?[T]()

mutating?func?push(item:?T)?{

items.append(item)

}

mutating?func?pop(item:?T)?->?T?{

returnitems.removeLast()

}

}

首先在函數(shù)名后面加<泛型類型名>,<>里面表明類型參數(shù)名。然后在函數(shù)主體里面完成跟非泛型棧類似的功能。這樣這個(gè)泛型結(jié)構(gòu)體就不只能壓棧Int類型的值,還可以是其它類型

[objc]view plaincopy

var?stack?=?Stack()//要在類型名后面加<類型名>

stack.push("uno")

stack.push("dos")

stack.push("tres")

stack.push("cuatro")

print(stack.pop())//?cuatro

6.擴(kuò)展一個(gè)泛型類型

可以擴(kuò)展一個(gè)泛型類型,給這個(gè)泛型類型添加屬性、方法、下標(biāo)等。

[objc]view plaincopy

extension?Stack{

//給泛型Stack擴(kuò)展一個(gè)計(jì)算型屬性topItem,返回最上面的item

vartopItem:?T??{

returnitems.isEmpty?nil:?items[items.count-1]

}

}

7.類型約束

在上面的SwapTwoVlues 和 Stack中,可以作用任何類型。但是也可以添加一個(gè)約束,比如指定一個(gè)類型必須采納某協(xié)議或者是指定類等。在Swift中(Bool,Int,Doube,String默認(rèn)都是哈希的),Dictionary的鍵就需要必須是可哈希的,方便字典查找是否已包含某個(gè)鍵的值。

類型約束語法

可以在類型參數(shù)名后面加一個(gè)類型或者協(xié)議名,通過冒號(hào)隔開,多個(gè)類型參數(shù)之間用逗號(hào)隔開

[objc]view plaincopy

func?somFuntion(someClass:?C,someProtocol:?P){

//這里用NSObject和NSObjectProtocol做例子

}

在定義的這個(gè)函數(shù)中,有兩個(gè)類型約束,第一次類型參數(shù)C代表是某個(gè)類,第二個(gè)參數(shù)P代表某個(gè)協(xié)議。

類型約束實(shí)踐

這個(gè)非泛型類型的方法用來查找某個(gè)字符串是否在字符數(shù)組中,存在返回index

[objc]view plaincopy

func?findStrInArray(_array:?[String],strToFind:?String)?->?Int?{

for(index,value)?in?array.enumerated(){

ifstrToFind?==?value{

returnindex

}

}

returnnil

}

下面這是針對(duì)上面非泛型方法泛型版本的方法

[objc]view plaincopy

func?findIndex?(_array:?[T],?_valueToFind:?T)?->?Int??{

for(index,value)?in?array.enumerated(){

ifvalue?==?valueToFind?{//如果沒指定S:Equatable?這句話會(huì)編譯不通過

returnindex

}

}

returnnil

}

在這個(gè)泛型例子中,不是所有的類型都可以 用 == 來比較的,所有必須指定泛型類型參數(shù)的約束為 Swift提供的 Equatable 協(xié)議,這表示T代表的類型必須是支持 Equatable 協(xié)議的。所有的Swift標(biāo)準(zhǔn)類型默認(rèn)都是支持Equatable協(xié)議的.

[objc]view plaincopy

let?value?=?findIndex([3.14159,0.1,0.25],9.3)

//?doubleIndex?類型為?Int?,其值為?nil,因?yàn)?9.3?不在數(shù)組中

let?stringIndex?=?findIndex(["Mike","Malcolm","Andrea"],"Andrea")

//?stringIndex?類型為?Int?,其值為?2

8.關(guān)聯(lián)類型

在定義協(xié)議的時(shí)候,有時(shí)候用一個(gè)或者多個(gè)關(guān)聯(lián)類型作為定義協(xié)議的一部分,關(guān)聯(lián)類型作為協(xié)議的一部分,為某個(gè)類型提供了一個(gè)占位符,其實(shí)際類型會(huì)在采納的時(shí)候被指定。并用關(guān)鍵字typealias 關(guān)鍵字來指定關(guān)聯(lián)名

關(guān)聯(lián)類型實(shí)踐

下面定義一個(gè)協(xié)議,協(xié)議指定了一個(gè)關(guān)聯(lián)類型

[objc]view plaincopy

protocol?Container{

associatedtype?itemType//聲明一個(gè)關(guān)聯(lián)類型

mutating?func?appended(item:?itemType)

varcount:?Int{?get?}

subscript(i:?Int)?->?itemType?{?get?}

}

下面是非泛型的版本采納 Container 協(xié)議

[objc]view plaincopy

structintStack:?Container?{

//?IntStack?的原始實(shí)現(xiàn)部分

var?items?=?[Int]()

mutating?func?push(item:?Int)?{

items.append(item)

}

mutating?func?pop()?->?Int?{

returnitems.removeLast()

}

//這里沒設(shè)置關(guān)聯(lián)類型的原因是根本不需要設(shè)置,因?yàn)楹艽_定只返回Int型,當(dāng)然你設(shè)置了也沒問題。

//?Container?協(xié)議的實(shí)現(xiàn)部分

mutating?func?appended(item:?Int)?{

self.push(item:?item)

}

varcount:?Int?{

returnitems.count

}

subscript(i:?Int)?->?Int?{

returnitems[i]

}

}

下面是一個(gè)泛型版本的

[objc]view plaincopy

structgenericStack:?Container{

//?genericStack?的原始實(shí)現(xiàn)部分

var?items?=?[T]()

mutating?func?push(item:?T)?{

items.append(item)

}

mutating?func?pop()?->?T?{

returnitems.removeLast()

}

//這是設(shè)置關(guān)聯(lián)類型具體是什么類型

typealias?itemType?=?T

//?Container?協(xié)議的實(shí)現(xiàn)部分

mutating?func?appended(item:?T)?{

self.push(item:?item)

}

varcount:?Int?{

returnitems.count

}

subscript(i:?Int)?->?T?{

returnitems[i]

}

}

通過擴(kuò)展一個(gè)存在類型來指定關(guān)聯(lián)類型

通過擴(kuò)展添加協(xié)議的一致性描述了如何利用一個(gè)已存在類型符合一個(gè)協(xié)議,這包括了使用關(guān)聯(lián)協(xié)議

Swift中的Array都滿足了Container協(xié)議的要求,意味著可以擴(kuò)展Array采納Container協(xié)議,你可以通過一個(gè)空擴(kuò)展來實(shí)現(xiàn)這點(diǎn).

[objc]view plaincopy

extension?Array?:Container{

mutating?internal?func?appended(item:?Element)?{}

}

定義這個(gè)擴(kuò)展之后,可以用Array當(dāng)做Container類型使用。

9.Where子句

類型約束能夠讓我們?yōu)榉盒皖愋吞砑右恍┘s束和條件。為關(guān)聯(lián)類型添加一些約束也是很有必要的。可以在參數(shù)列表中使用where子句來為關(guān)聯(lián)類型添加約束。

下面的例子判斷兩個(gè)采納Container協(xié)議的類型是否所有的元素順序及值都相等。

[objc]view plaincopy

func?allItemsMatch(someContainer:?C1,_anotherContainer:?C2)?->?Bool?where?C1.itemType==?C2.itemType,?C1.itemType:?Equatable?{

ifsomeContainer.count!=?anotherContainer.count{

returnfalse

}

fori?in0...someContainer.count-1{

ifsomeContainer[i]?!=?anotherContainer[i]{

returnfalse

}

}

returntrue

}

這個(gè)泛型函數(shù)在類型參數(shù)里面添加了where子句約束,C1,C2都必須是采納Container協(xié)議的類型,并且C1、C2的泛型類型必須相同,而且C1的泛型類型必須是采納Equatable的。

[objc]view plaincopy

var?stackOfStrings?=?genericStack()

stackOfStrings.appended(item:"uno")

stackOfStrings.appended(item:"dos")

stackOfStrings.appended(item:"tres")

var?arrayOfStrings?=?["uno","dos","tres"]//array類型的滿足Container類型,參考上面的extension?Array

ifallItemsMatch(stackOfStrings,?arrayOfStrings)?{

print("All?items?match.")

}else{

print("Not?all?items?match.")

}

//結(jié)果是:All?items?match.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容