Swift學(xué)習(xí):泛型

本篇將詳細(xì)總結(jié)介紹Swift泛型的用法;
Swift泛型代碼讓你能夠根據(jù)自定義的需求,編寫出適用于任意類型、靈活可重用的函數(shù)及類型。它能讓你避免代碼的重復(fù),用一種清晰和抽象的方式來表達(dá)代碼的意圖。

主要內(nèi)容:
1.泛型解決的問題
2.泛型函數(shù)
3.泛型類型
4.擴(kuò)展一個泛型類型
5.泛型的類型約束
6.關(guān)聯(lián)類型

一、泛型解決的問題

Swift泛型代碼讓你能夠根據(jù)自定義的需求,編寫出適用于任意類型、靈活可重用的函數(shù)及類型。它能讓你避免代碼的重復(fù),用一種清晰和抽象的方式來表達(dá)代碼的意圖。這種說法很模糊,下面我們結(jié)合一個示例來說明泛型的作用。
需求描述:使用函數(shù)來交換兩個變量的值

//互換兩個整型
func swapTwoInt(a:inout Int , b:inout Int){
    (a, b) = (b, a)
}

//互換兩個Double
func swapTwoDouble(a:inout Double, b:inout Double){
    (a,b) = (b,a)
}

代碼分析:
swapTwoInt與swapTwoDouble兩個函數(shù)功能相同,唯一的區(qū)別就是傳入的變量類型不同。這樣的代碼看起來重復(fù)又累贅。在實(shí)際應(yīng)用中,通常需要一個更實(shí)用更靈活的函數(shù)來交換兩個任意類型的值,幸運(yùn)的是,泛型代碼幫你解決了這種問題。

二、泛型函數(shù)

泛型函數(shù)可以適用于任何類型,下面的swapTwoValues(::)函數(shù)是上面兩個函數(shù)的泛型版本,可以交換任意類型的兩個變量。
尖括號里聲明一種通用類型T,參數(shù)列表里可以使用這種類型名表示通用類型

func SwapTwoThing<T>(a:inout T, b:inout T){
    (a, b) = (b, a)
}

var a = 100
var b = 200
swapTwoInt(a: &a , b: &b)
a  //200
b  //100

var string1 = "hello"
var string2 = "world"
SwapTwoThing(a: &string1, b: &string2)
string1  //world
string2  //hello

總結(jié)泛型函數(shù)的使用:
1.使用了占位類型名(T),來替換實(shí)際類型名(Int,Double);
2.占位類型符并不指定T必須是什么類型,但是卻限制了參數(shù)a和b必須是同一種類型T;
3.只有SwapTwoValues<T>(:)函數(shù)在調(diào)用時,才能根據(jù)所傳入的實(shí)際類型決定T所代表的類型;
4.T只是一個符號,可以使用大寫字母開頭的駝峰命名法(例如T和MyTypeParameter)來為類型參數(shù)命名,以表明它們是占位類型,而不是一個值。

三、泛型類型

3.1.系統(tǒng)類型使用到的泛型

事實(shí)上,泛型類型的使用貫穿了Swift語言。例如,Swift的Array和Dictionary都是泛型集合。你可以創(chuàng)建一個Int數(shù)組,也可創(chuàng)建一個String數(shù)組。

let arr = Array<Int>()
let dict = Dictionary<String,Int>()
let set  = Set<Float>()

3.2.自定義泛型類型:實(shí)現(xiàn)一個棧結(jié)構(gòu)體

除了泛型函數(shù),Swift還允許你定義泛型類型;這些自定義類、結(jié)構(gòu)體和枚舉可以適用于任何類型,類似于Array和 Dictionary。下面的示例就是創(chuàng)建一個具有棧功能的結(jié)構(gòu)體,適用于各種類型。

struct Stack<Element>{
    //存放棧中變量的數(shù)組
    var items = Array<Element>()
    
    //入棧:向棧中添加一個新元素
    mutating func push(item:Element){
        items.append(item)
    }
    
    //出棧:刪除棧頂元素,并返回此元素
    mutating func pop() ->Element?{
        return items.removeLast()
    }
}

var stack = Stack<Int>()
stack.push(item: 11)
stack.push(item: 22)
stack.pop()   //22

var stack1 = Stack<String>()
stack1.push(item:"aaa")
stack1.push(item:"bbb")
stack1.pop()  //“bbb"

3.3.自定義泛型類型:多個占位符

自定義泛型類型可以設(shè)置多個類型占位符,下面就是自定義了一個泛型類型Pair,它具有兩個占位類型符。

struct Pair<T1, T2>{
    var t1:T1
    var t2:T2
}
var pair1 = Pair(t1: "hello", t2: "hi")
print(pair1)   //Pair<String, String>(t1: "hello", t2: "hi")
var pair2:Pair<String, Int> = Pair(t1:"hello",t2: 123)
print(pair2)   //Pair<String, Int>(t1: "hello", t2: 123)

四、擴(kuò)展一個泛型類型

擴(kuò)展一個泛型類型,可以直接使用原始類型定義中聲明的類型參數(shù)列表,并且這些來自原始類型中的參數(shù)名稱會被用作原始定義中類型參數(shù)的引用。
比如,我們現(xiàn)在擴(kuò)展泛型類型Stack,為其添加計(jì)算型屬性topItem,用于獲取棧頂元素,代碼示例如下:

extension Stack {
    //返回當(dāng)前棧頂元素而不會將其從棧中移除
    var topItem: Element? {
        return items.isEmpty ? nil : items[items.count - 1]
    }
}
var stack3 = Stack<Int>()
stack3.push(item:1)
stack3.push(item:2)
stack3.push(item: 3)
if let topItem = stack3.topItem{
    print("棧頂元素:\(topItem)")   //棧頂元素:3
}

注意:擴(kuò)展中的占位類型符需要與原始類保持一致,所以這里用的還是Element。

五、泛型的類型約束

swapTwoValues(::)函數(shù)和Stack類型可以作用于任何類型。但如果可以為泛型函數(shù)和泛型類型的類型添加一個特定的類型約束,將會是非常有用的。
通常情況下,我們設(shè)置泛型類型約束的時候,會指定一個類型參數(shù)必須繼承自指定類,或者符合一個特定的協(xié)議或協(xié)議組合。

5.1.類型約束語法

對泛型函數(shù)添加類型約束的基本語法如下所示(作用于泛型類型時的語法與之相同)。

//在一個類型參數(shù)名后面放置一個類名或者協(xié)議名,并用冒號進(jìn)行分隔,來定義類型約束
func someFunction<T: SomeClass, U: SomeProtocol>(someT: T, someU: U) {
    // 這里是泛型函數(shù)的函數(shù)體部分
}

5.2.泛型類型約束實(shí)踐

下面的泛型函數(shù)用于查找數(shù)組中某個元素的索引位置;但由于for循環(huán)里用到了對象比較"==",要確保所有的類型都適用,所以在泛型函數(shù)的中添加了類型約束,使用此泛型函數(shù)的參數(shù)必須遵循Equatable協(xié)議。

func findIndex<T: Equatable>(of valueToFind: T, in array:[T]) -> Int? {
    for (index, value) in array.enumerated() {
        if value == valueToFind {
            return index
        }
    }
    return nil
}
let doubleIndex = findIndex(of: 9.3, in: [3.14159, 0.1, 0.25])  //nil
let stringIndex = findIndex(of: "Andrea", in: ["Mike", "Malcolm", "Andrea"]) //2

注意:Swift標(biāo)準(zhǔn)庫定義了Equatable協(xié)議,該協(xié)議要求任何遵循該協(xié)議的類型必須實(shí)現(xiàn)等式符(==)及不等符(!=)。從而能對該類型的任意兩個值進(jìn)行比較。所有的Swift標(biāo)準(zhǔn)類型自動支持 Equatable 協(xié)議

六、關(guān)聯(lián)類型

關(guān)聯(lián)類型是在為協(xié)議中的某個類型提供一個占位名,其所代表的實(shí)際類型會在協(xié)議被采納時才會被指定。這里涉及到兩個關(guān)鍵字,其作用就是給一個類型起一個別名,首先來說明一下:
associatedtype(協(xié)議聲明中使用)
typealias (協(xié)議實(shí)現(xiàn)中使用)
下面通過一個示例來理解關(guān)聯(lián)類型的作用:定義一個可稱重的協(xié)議,其中使用了泛型關(guān)聯(lián)類型。這種方式可以更大程度的使用協(xié)議,具體實(shí)現(xiàn)協(xié)議的時候再決定類型。

protocol WeightCaclulable{
    //associatedtype設(shè)置別名,即關(guān)聯(lián)類型
    associatedtype WeightType
    var weight:WeightType{get} //返回重量屬性,其類型是WeightType
}

//iphone7:手機(jī)較輕,表示重量時會有小數(shù)點(diǎn),所以使用Double描述
class Iphone7:WeightCaclulable{
    //實(shí)現(xiàn)的時候用的是typealias
    typealias WeightType  = Double
    
    var weight: Double {
        return 0.114
    }
}
//Ship:輪船較重,表示重量可以忽略小數(shù),所以使用Int描述
class Ship:WeightCaclulable{
    typealias WeightType = Int
    var weight: WeightType
    
    init(weight:WeightType) {
        self.weight = weight
    }
}
let iphone7 = Iphone7()
print(iphone7.weight)  //0.114
let ship = Ship(weight: 100000)
print(ship.weight)     //100000

6.1.關(guān)聯(lián)類型添加約束

協(xié)議中存在關(guān)聯(lián)類型,我們也可以為其添加約束,下面是一個Container協(xié)議,我們設(shè)置其關(guān)聯(lián)類型Item遵循了協(xié)議Equatable,具體代碼如下:

protocol Container {
    associatedtype Item: Equatable
    
    mutating func append(_ item: Item)
    var count: Int { get }
    subscript(i: Int) -> Item { get }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
禁止轉(zhuǎn)載,如需轉(zhuǎn)載請通過簡信或評論聯(lián)系作者。

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

  • 泛型代碼可以確保你寫出靈活的,可重用的函數(shù)和定義出任何你所確定好的需求的類型。你的可以寫出避免重復(fù)的代碼,并且用一...
    iOS_Developer閱讀 880評論 0 0
  • 本章將會介紹 泛型所解決的問題泛型函數(shù)類型參數(shù)命名類型參數(shù)泛型類型擴(kuò)展一個泛型類型類型約束關(guān)聯(lián)類型泛型 Where...
    寒橋閱讀 713評論 0 2
  • 136.泛型 泛型代碼讓你可以寫出靈活,可重用的函數(shù)和類型,它們可以使用任何類型,受你定義的需求的約束。你可以寫出...
    無灃閱讀 1,653評論 0 4
  • 泛型(Generics) 泛型代碼允許你定義適用于任何類型的,符合你設(shè)置的要求的,靈活且可重用的 函數(shù)和類型。泛型...
    果啤閱讀 758評論 0 0
  • 悠蘭噠閱讀 323評論 0 0

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