Swift中的泛型(Generics)

泛型(Generics)

1、泛型可以將類型參數化,提高代碼復用率,減少代碼量

func swapValue<T>(_ a: inout T, _ b: inout T) -> Void {
    (a, b) = (b, a)
}
var fn: (inout Int, inout Int) -> () = swapValue

class Stack<E> {
    var elements = [E]()
    func push(_ element: E) -> Void {
        elements.append(element)
    }
    
    func pop() -> E {
        elements.removeLast()
    }
    
    func top() -> E {
        elements.last!
    }
    
    func size() -> Int {
        elements.count
    }
}
 
var intStack = Stack<Int>()
var stringStack = Stack<String>()
var anyStack = Stack<Any>()

class SubStack<E>: Stack<E> {
    
}
struct Stack<E> {
    var elements = [E]()
    
    mutating func push(_ element: E) {
        elements.append(element)
    }
    
    mutating func pop() -> E {
        elements.removeLast()
    }
    
    func top() -> E {
        elements.last!
    }
    
    func size() -> Int {
        elements.count
    }
}

匯編分析泛型的實現(xiàn)原理


通過匯編我們可以看到兩次調用的swapValues方法的地址是相同的,也就是說是相同的方法,匯編中有關于metadata的信息,所以推測Swift中的泛型是通過對元數據的處理實現(xiàn)的。

關聯(lián)類型(Associated Type)

1、關聯(lián)類型的作用:給協(xié)議中用到的類型定義一個占位名稱

2、協(xié)議中可以擁有多個關聯(lián)類型

protocol Stackable {
    associatedtype Element
    mutating func push(_ element: Element)
    mutating func pop() -> Element
    func top() -> Element
    func size() -> Int
}
class StringStack: Stackable {
//    typealias Element = String 可寫可不寫
    var elements = [String]()
    func push(_ element: String) -> Void {
        elements.append(element)
    }
    
    func pop() -> String {
        elements.removeLast()
    }
    
    func top() -> String {
        elements.last!
    }
    
    func size() -> Int {
        elements.count
    }
}

類型約束

protocol Runnable {}
 
class Person {}
 
func swapValues<T: Person & Runnable>(_ a: inout T, _ b: inout T) -> Void {
    (a, b) = (b, a)
}

更多的約束

func equal<S1: Stackable, S2: Stackable>(_ s1: S1, _ s2: S2) -> Bool
where S1.Element == S2.Element, S1.Element: Hashable
{
    return false
}

協(xié)議類型的注意點

protocol Runnable {}
 
class Person: Runnable {}
 
class Car: Runnable {}
 
func getObject(_ type: Int) -> Runnable {
    if type == 0 {
        return Person()
    }
    return Car()
}
 
var r1 = getObject(0)
var r2 = getObject(1)

1、如果協(xié)議中有associatedtype,那么會有類型識別不了的問題,以下代碼會報錯

protocol Runnable {
    associatedtype Speed
    var speed: Speed {
        get
    }
}
 
class Person: Runnable {
    var speed: Double {
        0.0
    }
}
 
class Car: Runnable {
    var speed: Int {
        0
    }
}
 
func getObject(_ type: Int) -> Runnable {
    if type == 0 {
        return Person()
    }
    return Car()
}

泛型解決

解決方案1:使用泛型

protocol Runnable {
    associatedtype Speed
    var speed: Speed {
        get
    }
}
 
class Person: Runnable {
    var speed: Double {
        0.0
    }
}
 
class Car: Runnable {
    var speed: Int {
        0
    }
}
 
func getObject<T: Runnable>(_ type: Int) -> T {
    if type == 0 {
        return Person() as! T
    }
    return Car() as! T
}
 
var r1: Person = getObject(0)
var r2: Car = getObject(1)

不透明類型(Opaque Type)

1、解決方案2:使用some關鍵字聲明一個不透明類型

func getObject(_ type: Int) -> some Runnable {
    return Car()
}

2、some限制只能返回一種類型

some

1、some除了用在返回值類型上,一般還可以用在屬性類型上

protocol Runnable {
    associatedtype Speed
}
 
class Dog: Runnable {
    typealias Speed = Double
}
 
class Person {
    var pet: some Runnable {
        return Dog()
    }
}
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容