[Swift5.1] 16-泛型

泛型(Generics)

泛型函數(shù)

泛型可以將類型參數(shù)化,提高代碼復(fù)用率,減少代碼量

  • T代表 不確定類型參數(shù)
func swapValues<T>(_ a: inout T, _ b: inout T) {
    (a, b) = (b, a)
}


var i1 = 10  var i2 = 20
swapValues(&i1, &i2)

var d1 = 10.0  var d2 = 20.0
swapValues(&d1, &d2)

struct Date {
    var year = 0, month = 0, day = 0
}
var dd1 = Date(year: 2011, month: 9, day: 10)
var dd2 = Date(year: 2012, month: 10, day: 11)
swapValues(&dd1, &dd2)

泛型函數(shù)賦值給變量

func test<T1, T2>(_ t1: T1, _ t2: T2) {}
var fn: (Int, Double) -> () = test

泛型類型

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

var stack = Stack<Int>()
stack.push(11)
stack.push(22)
stack.push(33)
print(stack.top()) // 33
print(stack.pop()) // 33
print(stack.pop()) // 22
print(stack.pop()) // 11
print(stack.size()) // 0

class SubStack<E> : Stack<E> {}

注意: 修改結(jié)構(gòu)體數(shù)組元素, 需要添加mutating

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 }
}
enum Score<T> {
    case point(T)
    case grade(String)
}
let score0 = Score<Int>.point(100)
let score1 = Score.point(99)
let score2 = Score.point(99.5)
let score3 = Score<Int>.grade("A")

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

  • 關(guān)聯(lián)類型的作用:給協(xié)議中用到的類型定義一個(gè)占位名稱.
  • 協(xié)議中可以擁有多個(gè)關(guān)聯(lián)類型.(協(xié)議中使用泛型 只能用關(guān)聯(lián)類型)
protocol Stackable {
    associatedtype Element // 關(guān)聯(lián)類型
    mutating func push(_ element: Element)
    mutating func pop() -> Element
    func top() -> Element
    func size() -> Int
}
  • 類遵守協(xié)議, 給關(guān)聯(lián)類型設(shè)定真實(shí)類型
class StringStack : Stackable {
    // 給關(guān)聯(lián)類型設(shè)定真實(shí)類型, 也可以省略
    // typealias Element = String
    var elements = [String]()
    func push(_ element: String) { elements.append(element) }
    func pop() -> String { elements.removeLast() }
    func top() -> String { elements.last! }
    func size() -> Int { elements.count }
}
var ss = StringStack()
ss.push("Jack")
ss.push("Rose")
  • 類中泛型賦值給協(xié)議關(guān)聯(lián)類型
class Stack<E> : Stackable {
    // typealias Element = E
    var elements = [E]()
    func push(_ element: E) {
        elements.append(element)
    }
    func pop() -> E { elements.removeLast() }
    func top() -> E { elements.last! }
    func size() -> Int { elements.count }
}

類型約束

下面類型約束: 要求泛型必須是Person子類型和遵守Runnable協(xié)議

protocol Runnable { }
class Person { }
func swapValues<T : Person & Runnable>(_ a: inout T, _ b: inout T) {
    (a, b) = (b, a)
}
  • 協(xié)議中關(guān)聯(lián)類型也可以類型約束
protocol Stackable {
    associatedtype Element: Equatable
}
class Stack<E : Equatable> : Stackable { typealias Element = E }


func equal<S1: Stackable, S2: Stackable>(_ s1: S1, _ s2: S2) -> Bool  where S1.Element == S2.Element, S1.Element : Hashable {
    return false
}
var stack1 = Stack<Int>()
var stack2 = Stack<String>()
// error: requires the types 'Int' and 'String' be equivalent
equal(stack1, stack2)

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

protocol Runnable {}
class Person : Runnable {}
class Car : Runnable {}

func get(_ type: Int) -> Runnable {
    if type == 0 {
        return Person()
    }
    return Car()
}
var r1 = get(0)
var r2 = get(1)
  • 如果協(xié)議中有associatedtype, 以下寫法會(huì)報(bào)錯(cuò).
protocol Runnable {
    associatedtype Speed
    var speed: Speed { get }
}
class Person : Runnable {
    var speed: Double { 0.0 }
}
class Car : Runnable {
    var speed: Int { 0 }
}

func get(_ type: Int) -> Runnable {
    if type == 0 {
        return Person()
    }
    return Car()
}
var r1 = get(0)
var r2 = get(1)
  • 因?yàn)榫幾g后, 不確定關(guān)聯(lián)類型是什么類型.

1)泛型解決

解決方案①:使用泛型

func get<T : Runnable>(_ type: Int) -> T {
    if type == 0 {
        return Person() as! T
    }
    return Car() as! T
}
var r1: Person = get(0)
var r2: Car = get(1)

2)不透明類型(Opaque Type)

解決方案②:使用some關(guān)鍵字聲明一個(gè)不透明類型

func get(_ type: Int) -> some Runnable { Car() }
var r1 = get(0)
var r2 = get(1)

some限制只能返回一種類型


some

應(yīng)用: 想返回遵守某個(gè)協(xié)議對(duì)象, 不希望外部知道對(duì)象類型, 外部使用對(duì)象時(shí)只想暴露協(xié)議接口調(diào)用, 可以用不透明類型.

  • some除了用在返回值類型上,一般還可以用在屬性類型上
protocol Runnable { associatedtype Speed }
class Dog : Runnable { typealias Speed = Double }
class Person {
    var pet: some Runnable {
        return Dog()
    }
}

可選項(xiàng)的本質(zhì)

  • 可選項(xiàng)的本質(zhì)是enum類型

1)可選項(xiàng)在.h中定義

public enum Optional<Wrapped> : ExpressibleByNilLiteral {
    case none
    case some(Wrapped)
    public init(_ some: Wrapped)
}

2)以下可選項(xiàng)賦值等效

var age: Int? = 10
var age0: Optional<Int> = Optional<Int>.some(10)
var age1: Optional = .some(10)
var age2 = Optional.some(10)
var age3 = Optional(10)
age = nil
age3 = .none
var age: Int? = nil
var age0 = Optional<Int>.none
var age1: Optional<Int> = .none

3)可選項(xiàng)混寫

var age: Int? = .none
age = 10
age = .some
age = nil

4)可選類型可用于swich

switch age {
case let v?:   //如果可選類型age 有值, 會(huì)解包賦值給v
    print("some", v)
case nil:    //如果可選類型age為 nil 
    print("none")
}

switch age {
case let .some(v):
    print("some", v)
case .none:
    print("none")
}

等價(jià)于

if let v = age {
    print("some", v)
} else {
    print("none")
}

多重可選項(xiàng)的本質(zhì)

var age_: Int? = 10
var age: Int?? = age_
age = nil

等價(jià)于

var age0 = Optional.some(Optional.some(10))
age0 = .none
var age1: Optional<Optional> = .some(.some(10))
age1 = .none
var age: Int?? = 10
var age0: Optional<Optional> = 10
最后編輯于
?著作權(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),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
禁止轉(zhuǎn)載,如需轉(zhuǎn)載請(qǐng)通過簡(jiǎn)信或評(píng)論聯(lián)系作者。

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

  • 一、錯(cuò)誤處理 1.1、錯(cuò)誤類型語法錯(cuò)誤(編譯報(bào)錯(cuò))邏輯錯(cuò)誤運(yùn)行時(shí)錯(cuò)誤(可能會(huì)導(dǎo)致閃退,一般也叫做異常) 1.2、自...
    IIronMan閱讀 695評(píng)論 0 3
  • 泛型函數(shù) 泛型可以將類型參數(shù)化,提高代碼復(fù)用率,減少代碼量 看個(gè)例子??,交換兩個(gè)變量的值:定義一個(gè)函數(shù),參數(shù)為in...
    SAW_閱讀 211評(píng)論 0 1
  • 泛型可以將類型參數(shù)話,提高代碼的復(fù)用率,減少代碼量 泛型的簡(jiǎn)單使用 假設(shè)我們要對(duì)兩個(gè)值進(jìn)行交換,我們需要寫這么多方...
    SunshineBrother閱讀 213評(píng)論 0 2
  • 泛型(Generics) 泛型可以將類型參數(shù)化,提高代碼復(fù)用率,減少代碼量 泛型函數(shù)賦值給變量 關(guān)聯(lián)類型(Asso...
    Stago閱讀 211評(píng)論 0 0
  • 在 Swift 中可以通過Error協(xié)議自定義運(yùn)行時(shí)的錯(cuò)誤信息.任何實(shí)現(xiàn)了Error協(xié)議的枚舉,結(jié)構(gòu)體,類都可以自...
    小心韓國(guó)人閱讀 790評(píng)論 0 2

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