Swift底層原理-Sequence與Collection

Swift底層原理-Sequence與Collection

  • Sequence協(xié)議來說拙绊,表達(dá)的是既可以是一個(gè)有限的集合呐萌,也可以是一個(gè)無限的集合弊予,而它只需要提供集合中的元素和如何訪問這些元素的接口即可翼岁。
  • Collection協(xié)議是建立在Sequence協(xié)議之上的悦析,為有限的序列提供下標(biāo)訪問的能力寿桨,同時(shí)增加了count屬性,自定義索引等特性

[圖片上傳失敗...(image-e4a786-1684654022077)]

Sequence

  • Sequence作為swift集合類協(xié)議擴(kuò)展方法强戴,為集合提供了一系列的序列迭代能力亭螟。

for in本質(zhì)

  • Sequence是通過Iterator來訪問元素的挡鞍。Iterator是一個(gè)迭代器,我們來看一段代碼预烙,如下:
let nums = [1, 2, 3, 4, 5];
for element in nums {
    print(element)
}
  • Swift中的 for in 其實(shí)是一個(gè)語法糖墨微,那么它的本質(zhì)是什么呢,我們把它編譯成sil的代碼來看一下
// main
sil [ossa] @main : $@convention(c) (Int32, UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>) -> Int32 {
bb0(%0 : $Int32, %1 : $UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>):
  alloc_global @$s4main4numsSaySiGvp              // id: %2
  // 省略部分代碼
  %49 = alloc_stack $Array<Int>                   // users: %53, %52, %50
  store %48 to [init] %49 : $*Array<Int>          // id: %50
  %51 = witness_method $Array<Int>, #Sequence.makeIterator : <Self where Self : Sequence> (__owned Self) -> () -> Self.Iterator : $@convention(witness_method: Sequence) <τ_0_0 where τ_0_0 : Sequence> (@in τ_0_0) -> @out τ_0_0.Iterator // user: %52
  %52 = apply %51<[Int]>(%47, %49) : $@convention(witness_method: Sequence) <τ_0_0 where τ_0_0 : Sequence> (@in τ_0_0) -> @out τ_0_0.Iterator
  dealloc_stack %49 : $*Array<Int>                // id: %53
  br bb1                                          // id: %54

bb1:                                              // Preds: bb3 bb0
  %55 = alloc_stack $Optional<Int>                // users: %61, %60, %58
  %56 = begin_access [modify] [unknown] %47 : $*IndexingIterator<Array<Int>> // users: %59, %58
  %57 = witness_method $IndexingIterator<Array<Int>>, #IteratorProtocol.next : <Self where Self : IteratorProtocol> (inout Self) -> () -> Self.Element? : $@convention(witness_method: IteratorProtocol) <τ_0_0 where τ_0_0 : IteratorProtocol> (@inout τ_0_0) -> @out Optional<τ_0_0.Element> // user: %58
  %58 = apply %57<IndexingIterator<Array<Int>>>(%55, %56) : $@convention(witness_method: IteratorProtocol) <τ_0_0 where τ_0_0 : IteratorProtocol> (@inout τ_0_0) -> @out Optional<τ_0_0.Element>
  end_access %56 : $*IndexingIterator<Array<Int>> // id: %59
  %60 = load [trivial] %55 : $*Optional<Int>      // user: %62
  dealloc_stack %55 : $*Optional<Int>             // id: %61
  switch_enum %60 : $Optional<Int>, case #Optional.some!enumelt: bb3, case #Optional.none!enumelt: bb2 // id: %62
  • 我們可以看到在%51行扁掸,調(diào)用了Sequence.makeIterator方法翘县,創(chuàng)建一個(gè)Iterator,把數(shù)組傳給迭代器也糊。
  • %57行炼蹦,調(diào)用IteratorProtocol.next方法,將數(shù)組元素遍歷出來狸剃。

Sequence與IteratorProtocol

  • 我們來Sequence.swift這個(gè)文件掐隐,查看Sequence定義
public protocol Sequence {
  // 可在協(xié)議實(shí)現(xiàn)后確定協(xié)議類型
  associatedtype Element

  associatedtype Iterator: IteratorProtocol where Iterator.Element == Element
  
  // 獲取一個(gè)迭代器
  /// Returns an iterator over the elements of this sequence.
  __consuming func makeIterator() -> Iterator

  // 省略其他方法
}
  • 在該協(xié)議中,最重要的就是創(chuàng)建了一個(gè)迭代器

  • 查看一下IteratorProtocol定義

public protocol IteratorProtocol {
    /// The type of element traversed by the iterator.
    associatedtype Element

    mutating func next() -> Self.Element?
}
  • 它有一個(gè)next方法钞馁,可以通過調(diào)用next方法來返回元素虑省。
  • 所以我們每次在使用 for..in 的時(shí)候,其實(shí)都是 通過sequence創(chuàng)建一個(gè)迭代器僧凰,用這個(gè)集合的迭代器來遍歷當(dāng)前集合或者序列當(dāng)中的元素

自己定義一個(gè)遵循Sequence的結(jié)構(gòu)體

  • 自定義可迭代結(jié)構(gòu)體
struct TestSequence: Sequence {
    typealias Element = Int
    typealias Iterator = TestIterator
    let count: Int
    
    // MARK: - initialization
    init(count: Int) {
        self.count = count
    }
    
    func makeIterator() -> TestIterator {
        return TestIterator(sequece: self)
    }
}

struct TestIterator: IteratorProtocol {
    typealias Element = Int
    let sequece: TestSequence
    var count = 0
    
    // MARK: - initialization
    init(sequece: TestSequence) {
        self.sequece = sequece
    }
    
    mutating func next() -> Int? {
        guard count < sequece.count else {
            return nil
        }
        count += 1
        return count
    }
}

let seq = TestSequence(count: 5)
for element in seq {
    print(element)
}

打印結(jié)果:

1

2

3

4

5

Collection

  • Collection協(xié)議實(shí)現(xiàn)了Sequence協(xié)議探颈,為有限的序列提供下標(biāo)訪問的能力,同時(shí)增加了count屬性训措,自定義索引等特性伪节。

  • Collection是一個(gè)序列,其元素可以被多次遍歷绩鸣。通過定義startIndexendIndex屬性怀大,表示集合起始和結(jié)束位置。

  • 我們看一下colletcion定義

public protocol Collection: Sequence {
  // FIXME: ideally this would be in MigrationSupport.swift, but it needs
  // to be on the protocol instead of as an extension
  @available(*, deprecated/*, obsoleted: 5.0*/, message: "all index distances are now of type Int")
  typealias IndexDistance = Int  

  // FIXME: Associated type inference requires this.
  override associatedtype Element

  associatedtype Index: Comparable

  var startIndex: Index { get } 

  var endIndex: Index { get }

  // sequence協(xié)議的實(shí)現(xiàn)
  associatedtype Iterator = IndexingIterator<Self>

  override __consuming func makeIterator() -> Iterator

  associatedtype SubSequence: Collection = Slice<Self>
  where SubSequence.Index == Index,
        Element == SubSequence.Element,
        SubSequence.SubSequence == SubSequence

  func index(after i: Index) -> Index
   
  // 省略部分方法
}
  • 遵循Collection協(xié)議呀闻,此時(shí)我們就需要實(shí)現(xiàn) startIndex化借、endIndexindex(after:) 方法,index(after:) 是為了便于移動(dòng)當(dāng)前索引的位置捡多。

mutableCollection

  • mutableCollection定義
public protocol MutableCollection: Collection
where SubSequence: MutableCollection
{
  // FIXME: Associated type inference requires these.
  override associatedtype Element
  override associatedtype Index
  override associatedtype SubSequence

  @_borrowed
  override subscript(position: Index) -> Element { get set }

  override subscript(bounds: Range<Index>) -> SubSequence { get set }

  mutating func partition(
    by belongsInSecondPartition: (Element) throws -> Bool
  ) rethrows -> Index

  mutating func swapAt(_ i: Index, _ j: Index)
  
  mutating func _withUnsafeMutableBufferPointerIfSupported<R>(
    _ body: (inout UnsafeMutableBufferPointer<Element>) throws -> R
  ) rethrows -> R?

  mutating func withContiguousMutableStorageIfAvailable<R>(
    _ body: (inout UnsafeMutableBufferPointer<Element>) throws -> R
  ) rethrows -> R?
}
  • 遵循該協(xié)議蓖康,實(shí)現(xiàn)了下標(biāo)的setter方法,便于在語法上直接通過下標(biāo)來訪問并修改這個(gè)元素的值垒手。

RangeReplaceableCollection

  • RangeReplaceableCollection允許集合修改任意區(qū)間的元素
public protocol RangeReplaceableCollection: Collection
  where SubSequence: RangeReplaceableCollection {
  // FIXME: Associated type inference requires this.
  override associatedtype SubSequence

  /// Creates a new, empty collection.
  init()

  mutating func replaceSubrange<C>(
    _ subrange: Range<Index>,
    with newElements: __owned C
  ) where C: Collection, C.Element == Element

  mutating func reserveCapacity(_ n: Int)

  init(repeating repeatedValue: Element, count: Int)

  init<S: Sequence>(_ elements: S)
    where S.Element == Element

  mutating func append(_ newElement: __owned Element)

  mutating func append<S: Sequence>(contentsOf newElements: __owned S)
    where S.Element == Element

  mutating func insert(_ newElement: __owned Element, at i: Index)
 
  @discardableResult
  mutating func remove(at i: Index) -> Element

  mutating func removeSubrange(_ bounds: Range<Index>)

  mutating func _customRemoveLast() -> Element?

  mutating func _customRemoveLast(_ n: Int) -> Bool

  @discardableResult
  mutating func removeFirst() -> Element

  mutating func removeFirst(_ k: Int)

  mutating func removeAll(keepingCapacity keepCapacity: Bool /*= false*/)

  // 省略部分方法
}
  • 除此之外還有很多針對(duì)集合的協(xié)議蒜焊,比如說BidirectionalCollection可以向前或向后遍歷集合;RandomAccessCollection可以任意訪問集合元素等。
  • 根據(jù)功能的不同劃分科贬,定義在不同的協(xié)議里面山涡,符合借口單一原則,通過協(xié)議的組合,可以達(dá)到不同復(fù)雜度的集合鸭丛。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末竞穷,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子鳞溉,更是在濱河造成了極大的恐慌瘾带,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,188評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件熟菲,死亡現(xiàn)場(chǎng)離奇詭異看政,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)抄罕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,464評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門允蚣,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人呆贿,你說我怎么就攤上這事嚷兔。” “怎么了做入?”我有些...
    開封第一講書人閱讀 165,562評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵冒晰,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我竟块,道長(zhǎng)壶运,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,893評(píng)論 1 295
  • 正文 為了忘掉前任浪秘,我火速辦了婚禮蒋情,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘耸携。我一直安慰自己棵癣,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,917評(píng)論 6 392
  • 文/花漫 我一把揭開白布违帆。 她就那樣靜靜地躺著浙巫,像睡著了一般金蜀。 火紅的嫁衣襯著肌膚如雪刷后。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,708評(píng)論 1 305
  • 那天渊抄,我揣著相機(jī)與錄音尝胆,去河邊找鬼。 笑死护桦,一個(gè)胖子當(dāng)著我的面吹牛含衔,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 40,430評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼贪染,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼缓呛!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起杭隙,我...
    開封第一講書人閱讀 39,342評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤哟绊,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后痰憎,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體票髓,經(jīng)...
    沈念sama閱讀 45,801評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,976評(píng)論 3 337
  • 正文 我和宋清朗相戀三年铣耘,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了洽沟。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,115評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡蜗细,死狀恐怖裆操,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情鳄乏,我是刑警寧澤跷车,帶...
    沈念sama閱讀 35,804評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站橱野,受9級(jí)特大地震影響朽缴,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜水援,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,458評(píng)論 3 331
  • 文/蒙蒙 一密强、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧蜗元,春花似錦或渤、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,008評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至惯豆,卻和暖如春池磁,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背楷兽。 一陣腳步聲響...
    開封第一講書人閱讀 33,135評(píng)論 1 272
  • 我被黑心中介騙來泰國打工地熄, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人芯杀。 一個(gè)月前我還...
    沈念sama閱讀 48,365評(píng)論 3 373
  • 正文 我出身青樓端考,卻偏偏與公主長(zhǎng)得像雅潭,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子却特,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,055評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容