如何自己實(shí)現(xiàn)一個(gè)Swift數(shù)組

原文鏈接:如何自己實(shí)現(xiàn)一個(gè)Swift數(shù)組

本文中,我們將會(huì)探索Swift原生Array數(shù)組的實(shí)現(xiàn)方式,并且自定義實(shí)現(xiàn)一個(gè)數(shù)組類型,能夠字面量來創(chuàng)建數(shù)組,通過下標(biāo)來獲取元素。

查看文檔我們發(fā)現(xiàn),Swift的數(shù)組是一個(gè)結(jié)構(gòu)體類型,它遵守了CollectionType、MutableCollectionType、_DstructorSafeContainer協(xié)議,其中最重要的就是CollectionType協(xié)議,數(shù)組的一些主要功能都是通過這個(gè)協(xié)議實(shí)現(xiàn)的。
CollectionType協(xié)議又遵守IndexableSequenceType這兩個(gè)協(xié)議。而在這兩個(gè)協(xié)議中,SequenceType協(xié)議是數(shù)組、字典等集合類型最重要的協(xié)議,在文檔中解釋了SequenceType是一個(gè)可以通過for...in循環(huán)迭代的類型,實(shí)現(xiàn)了這個(gè)協(xié)議,就可以for...in循環(huán)了。

A type that can be iterated with a for...in loop.

SequenceType是建立在GeneratorType基礎(chǔ)上的,sequence需要GeneratorType來告訴它如何生成元素。

GeneratorType

GeneratorType協(xié)議有兩部分組成:

  1. 它需要有一個(gè)Element關(guān)聯(lián)類型,這也是它產(chǎn)生的值的類型。
  2. 它需要有一個(gè)next方法。這個(gè)方法返回Element的可選對(duì)象。通過這個(gè)方法就可以一直獲取下一個(gè)元素,直到返回nil,就意味著已經(jīng)獲取到了所有元素。
/// Encapsulates iteration state and interface for iteration over a
/// sequence.
///
/// - Note: While it is safe to copy a generator, advancing one
///   copy may invalidate the others.
///
/// Any code that uses multiple generators (or `for`...`in` loops)
/// over a single sequence should have static knowledge that the
/// specific sequence is multi-pass, either because its concrete
/// type is known or because it is constrained to `CollectionType`.
/// Also, the generators must be obtained by distinct calls to the
/// sequence's `generate()` method, rather than by copying.
public protocol GeneratorType {
    /// The type of element generated by `self`.
    associatedtype Element
    /// Advance to the next element and return it, or `nil` if no next
    /// element exists.
    ///
    /// - Requires: `next()` has not been applied to a copy of `self`
    ///   since the copy was made, and no preceding call to `self.next()`
    ///   has returned `nil`.  Specific implementations of this protocol
    ///   are encouraged to respond to violations of this requirement by
    ///   calling `preconditionFailure("...")`.
    @warn_unused_result
    public mutating func next() -> Self.Element?
}

我把自己實(shí)現(xiàn)的數(shù)組命名為MYArray,generator為MYArrayGenerator,為了簡單,這里通過字典來存儲(chǔ)數(shù)據(jù),并約定字典的key為從0開始的連續(xù)數(shù)字。就可以這樣來實(shí)現(xiàn)GeneratorType:

/// 需保準(zhǔn)dic的key是從0開始的連續(xù)數(shù)字
struct MYArrayGenerator<T>: GeneratorType {
  private let dic: [Int: T]
  private var index = 0

  init(dic: [Int: T]) {
    self.dic = dic
  }

  mutating func next() -> T? {
    let element = dic[index]
    index += 1
    return element
  }
}


這里通過next方法的返回值,隱式地為Element賦值。顯式地賦值可以這樣寫typealias Element = T。要使用這個(gè)生成器就非常簡單了:

let dic = [0: "XiaoHong", 1: "XiaoMing"]

var generator = MYArrayGenerator(dic: dic)

while let elment = generator.next() {
  print(elment)
}
// 打印的結(jié)果:
// XiaoHong
// XiaoMing

SequenceType

有了generator,接下來就可以實(shí)現(xiàn)SequenceType協(xié)議了。SequenceType協(xié)議也是主要有兩部分:

  1. 需要有一個(gè)Generator關(guān)聯(lián)類型,它要遵守GeneratorType
  2. 要實(shí)現(xiàn)一個(gè)generate方法,返回一個(gè)Generator。
    同樣的,我們可以通過制定generate方法的方法類型來隱式地設(shè)置Generator:
struct MYArray<T>: SequenceType {
  private let dic: [Int: T]
    
  func generate() -> MYArrayGenerator<T> {
    return MYArrayGenerator(dic: dic)
  }
}

這樣我們就可以創(chuàng)建一個(gè)MYArray實(shí)例,并通過for循環(huán)來迭代:

let dic = [0: "XiaoHong", 1: "XiaoMing", 2: "XiaoWang", 3: "XiaoHuang", 4: "XiaoLi"]
let array = MYArray(dic: dic)

for value in array {
  print(value)
}

let names = array.map { $0 }

當(dāng)然,目前這個(gè)實(shí)現(xiàn)還存在很大的隱患,因?yàn)閭魅氲淖值涞膋ey是不可知的,雖然我們限定了必須是Int類型,但無法保證它一定是從0開始,并且是連續(xù),因此我們可以通過修改初始化方法來改進(jìn):

init(elements: T...) {
    dic = [Int: T]()
    elements.forEach { dic[dic.count] = $0 }
  }

然后我們就可以通過傳入多參數(shù)來創(chuàng)建實(shí)例了:

let array = MYArray(elements: "XiaoHong", "XiaoMing", "XiaoWang", "XiaoHuang", "XiaoLi")

再進(jìn)一步,通過實(shí)現(xiàn)ArrayLiteralConvertible協(xié)議,我們可以像系統(tǒng)的Array數(shù)組一樣,通過字面量來創(chuàng)建實(shí)例:

let array = ["XiaoHong", "XiaoMing", "XiaoWang", "XiaoHuang", "XiaoLi"]

最后還有一個(gè)數(shù)組的重要特性,就是通過下標(biāo)來取值,這個(gè)特性我們可以通過實(shí)現(xiàn)subscript方法來實(shí)現(xiàn):

extension MYArray {
  subscript(idx: Int) -> Element {
    precondition(idx < dic.count, "Index out of bounds")
    return dic[idx]!
  }
}

print(array[3]) // XiaoHuang

至此,一個(gè)自定義的數(shù)組就基本實(shí)現(xiàn)了,我們可以通過字面量來創(chuàng)建一個(gè)數(shù)組,可以通過下標(biāo)來取值,可以通過for循環(huán)來遍歷數(shù)組,可以使用map、forEach等高階函數(shù)。

小結(jié)

要實(shí)現(xiàn)一個(gè)數(shù)組的功能,主要是通過實(shí)現(xiàn)SequenceType協(xié)議。SequenceType協(xié)議有一個(gè)Generator實(shí)現(xiàn)GeneratorType協(xié)議,并通過Generator的next方法來取值,這樣就可以通過連續(xù)取值,來實(shí)現(xiàn)for循環(huán)遍歷了。同時(shí)通過實(shí)現(xiàn)ArrayLiteralConvertible協(xié)議和subscript,就可以通過字面量來創(chuàng)建數(shù)組,并通過下標(biāo)來取值。

CollectionType

上面我們?yōu)榱伺宄?code>SequenceType的實(shí)現(xiàn)原理,通過實(shí)現(xiàn)SequenceTypeGeneratorType來實(shí)現(xiàn)數(shù)組,但實(shí)際上Swift系統(tǒng)的Array類型是通過實(shí)現(xiàn)CollectionType來獲得這些特性的,而CollectionType協(xié)議又遵守IndexableSequenceType這兩個(gè)協(xié)議。并擴(kuò)展了兩個(gè)關(guān)聯(lián)類型GeneratorSubSequence,以及9個(gè)方法,但這兩個(gè)關(guān)聯(lián)類型都是默認(rèn)值,而且9個(gè)方法也都在協(xié)議擴(kuò)展中有默認(rèn)實(shí)現(xiàn)。
因此,我們只需要為Indexable協(xié)議中要求的 startIndexendIndex 提供實(shí)現(xiàn),并且實(shí)現(xiàn)一個(gè)通過下標(biāo)索引來獲取對(duì)應(yīng)索引的元素的方法。只要我們實(shí)現(xiàn)了這三個(gè)需求,我們就能讓一個(gè)類型遵守 CollectionType 了。因此這個(gè)自定義的數(shù)組可以這樣實(shí)現(xiàn):

struct MYArray<Element>: CollectionType {

  private var dic: [Int: Element]

  init(elements: Element...) {
    dic = [Int: Element]()
    elements.forEach { dic[dic.count] = $0 }
  }

  var startIndex: Int { return 0 }
  var endIndex: Int { return dic.count }
  subscript(idx: Int) -> Element {
    precondition(idx < endIndex, "Index out of bounds")
    return dic[idx]!
  }
}

extension MYArray: ArrayLiteralConvertible {
  init(arrayLiteral elements: Element...) {
    dic = [Int: Element]()
    elements.forEach { dic[dic.count] = $0 }
  }
}
最后編輯于
?著作權(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)容