swift-集合類型

數(shù)組

  1. 數(shù)組和可變性
    // 斐波那契數(shù)列
    let fibs = [0,1,1,2,3,5]
    不可變 不能用append(_:)
    var fibs = [0,1,1,2,3,5]
let 只能保證引用永遠不發(fā)生變化,而不能保證引用的值發(fā)生變化
標準庫里的集合類型都是有值語義的
let x = [1,2,3]
var y = x
y.append(4)
// x 123
// y 1234

let z = NSMutableArray(array: [1,2,3])
z.insert(4, at:3)
//z 是引用類型
  1. 數(shù)組和可選值
    標準庫的提供的 first last popLast 不會數(shù)組越界 而是 返回 Optional 它總會執(zhí)行邊界檢查
  2. Map Filter ....
  3. 數(shù)組切片
    數(shù)組切片不是Array,只是數(shù)組的一種表示方式,但是可以當做Array使用
let slice = fibs[1...<fibs.endIndex]
type(of: slice) // ArraySlice<Int>

字典

字典是無序的,字典是一種稀疏結構不能保證某個鍵下的值是否有值

  1. 可變性
  2. 擴展merge
extension Dictionary {
    mutating func merge<S>(_ other: S) where S: Sequence, S.Iterator.Element == (key: Key, value: Value) {
        for (k, v) in other {
            self[k] = v
        }
    }
}
// 這樣就可以合并字典了 而且參數(shù)可以是鍵值對數(shù)組或任意類似序列
  1. Hashable 要求
    字典其實是哈希表,字典通過鍵 hashValue 來確定值的位置
    標準庫中所有類型都支持 Hashable 要求

Set

無序且不重復

  1. 執(zhí)行集合代數(shù) SetAlgebra 協(xié)議
    Set 是標準庫中唯一實現(xiàn)了 SetAlgebra 協(xié)議的類型,而Foundation中有另外的IndexSet,CharacterSet 他們已經(jīng)被Swift以值的方式導入了

Range

范圍代表兩個值之間的區(qū)域let singleDigitNumbers = 0..<10, let lowercaseLetters = Character('a')...Character('z')
范圍看起來是一個序列或集合類型,但它并非兩者之一。

     | 半開范圍 | 閉合范圍

------- |----------|---------
Comparable | Range | ClosedRange
Strideable | CountableRange | CountableClosedRange

以整數(shù)為步長

  • 只有半開范圍能表達空間區(qū)的概念
  • 只有閉合范圍能包含元素類型的最大值 0...Int.max 半開范圍總是最少有一個值比范圍所表達的值要大 Int.max + 1 ???
  • 只有那些可數(shù)的區(qū)域才能 for in 遵循Sequence協(xié)議

集合類型協(xié)議 太難下次再講??

可選值

  1. 崗哨值

編程語言中有一種常見模式,那就是操作是否要返回一個有效的值

int ch;
while ((ch=getchar()) != EOF) {
        printf("Read character %c\n", ch);
}
printf("Reached end-of-file %c\n", ch);
  • EOF 是對 -1 的 #define 它代表未找到 或者 空值
    在各種語言中 null 最為常見
  • 函數(shù)返回一個代表并沒有返回真實的值的值,被稱為 崗哨值
  • 它容易被忽略檢測而產(chǎn)生錯誤
let s: NSString? = "..."
if s.range(of: "swift").location != NSNotFound {
    print("someone mentioned sift!")
}

如果someString 是 nil 將返回一個都是0的range 語句將會被執(zhí)行

  1. 通過枚舉解決問題 swift 的枚舉可包含另外的關聯(lián)值
enum Optional<Wrapped> {
    case none
    case some(Wrapped)
}
  • 和崗哨值不通 除非顯示的檢測解包否則你不可能意外使用到一個Optional中的值
  • index(of:) 就會返回一個Optional<Index>的值 它遵守ExpressibleByNilLiteral協(xié)議 可以寫作 Index? 用 nil 代替.none
  • 如果你要使用返回的值 就必須解包
  1. if let
  2. while let
    在 Swift 中 for in 其實就是 where let 來實現(xiàn)的 避免了閉包的值捕獲問題
a = []
for i in 1..3 {
        a.push(lambda{i})
}

for f in a {
        print "#{f.call()}"
}
輸出 ???
  1. 雙重可選值 Optional<Optional<Int>> 系統(tǒng)會自動解包一層
  2. if var and while var
  3. guard 可以 擴大 可選作用域
  4. 可選鏈 OC 中nil 不會發(fā)消息 執(zhí)行方法 swift中 ?可選鏈實現(xiàn)了同樣的效果
  5. 合并運算符 ??
  6. 可選值map
let characters = ["a","b"]
let string = String(characters.first)
編譯失敗
可以寫成
let string = characters.first.map{ String($0) }
  1. flatMap
let numbers = ["1","foo"]
let x = numbers.first.map{ Int($0) } //Optional<Optional<Int>>

let x = numbers.first.flatMap{ Int($0) } //Optional<Int>
  1. 比較 我們可以 寫出代碼 if numbers.first == "1" 而不需要加 Optional("1") 然而 [Int?] == [Int?] 是不可以的 因為 == 需要數(shù)組元素遵守Equable 協(xié)議
  2. 改進強制解包錯誤信息
func !! <T>(wrapped: T?, failureText: @autoclosure ()-> String) -> T {
    if let x = wrapped {
        return x
    }
    fatalError(failureText())
}
let ss = "foo"
let i = Int(ss) !! "nonono, get \"\(ss)\""
崩潰前執(zhí)行
  1. 隱式可選值
var s: String! = "s"

在行為上它表現(xiàn)的像是非可選值,但它還可以使用可選值 的可選鏈 if let 等

集合類型協(xié)議

在之前,我們看到了 Array Dictionary 和 Set,它們并非空中樓閣,而是建立在一系列由 Swift 標準庫提供的用于處理元素序列的抽象之上的。
Sequence 和 collection協(xié)議,它們構成了這套集合類型模型的基石。本章會研究這些協(xié)議是如何工作的,它們?yōu)槭裁匆赃@樣的方式工作,以及如何寫出自己的序列和集合類型等
  1. 序列
    Sequence協(xié)議是集合序列的基礎,代表的是一系列具有相同類型的值,你可以對這些值進行迭代。遍歷一個序列最簡單的方式是使用for循環(huán)
for element in someSequence {
doSomething(with: element)
}

Sequence協(xié)議提供了許多強大的功能,滿足該協(xié)議的類型都可以直接使用這些功能。上面這樣步進式地迭代元素的能力看起來十分簡單,但它卻是 Sequence可以提供這些強大功能的基礎。在上一章中已經(jīng)提到過不少這類功能了,每當你遇到一個能夠針對元素序列進行的通用的操作,你都應該考慮將它實現(xiàn)在 Sequence層可能性。在接下來的部分,會看到許多這方面的例子。
滿足 Sequence 協(xié)議非常簡單 只需要提供一個返回迭代器iteratormakeIterator()方法:

 protocol Sequence {
        associatedtype Iterator: IteratorProtocol
      func makeIterator()->Iterator
 }
 

對于迭代器,我們現(xiàn)在只能從 Sequence 的定于中看出他滿足 IteratorProtocol協(xié)議的類型。所以首先來仔細看看迭代器是什么。

  1. 迭代器
    序列通過一個迭代器來訪問元素 IteratorProtocol 協(xié)議中有一個next()方法返回序列中下一個元素的值直到序列耗盡返回 nil
protocol IteratorProtocol {
        associatedtype Element
        mutating func next() -> Element?
}
本質(zhì)上for循環(huán)就是下面代碼的簡寫 當然我們也可創(chuàng)造無限序列
var iterator = someSequence.makeIterator()
while let element = iterator.next() {
    doSomething(with: element)
}

next 被標記mutating 看起來是不需要的 但實踐中迭代器本質(zhì)是存在狀態(tài)的

struct FibsIterator: IteratorProtocol {
        typealias Element = Int
    var state = (0, 1)
    mutating func next() -> Int? {
        let upcomingNumber = state.0
        state = (state.1, state.0 + state.1)
        return upcomingNumber
    }
}

基于函數(shù)的迭代器序列

func uniqueIntegerProvider() -> AnyIterator<Int> {
    var i = 0
    return AnyIterator {
        i += 1
        return i
    }
}

let prodiver = AnySequence(uniqueIntegerProvider)
Array(prodiver.prefix(10))

無限序列, sequence 的 next 閉包總是延時執(zhí)行的 也就是說 下一個next 不會被自動計算 prodiver.prefix(10) 只會求前10個
如果序列主動計算 它就會溢出崩潰
對集合和序列來說 區(qū)別之一 就是 序列可以無限 而集合不行

不穩(wěn)定序列 網(wǎng)絡流 UI時間流 磁盤文件 都可以用序列建模
網(wǎng)絡包這種序列將被遍歷消耗再次遍歷不能保證是同樣的值,
sequence 明確指出了不保證可以被多次遍歷

  1. 集合類型 Collection

是指那些穩(wěn)定的序列 能夠被多次遍歷并保存一致,可以下標訪問 有起始和終止索引。

Collection協(xié)議是基于Sequence來的除了繼承所有方法外,它還可以獲取指定位置的元素 獲取 穩(wěn)定的迭代的保證,count等新的特性

  1. (1)實現(xiàn)一個隊列 (2)遵守ExpressibleByArrayLiteral 協(xié)議 (3)關聯(lián)類型
// 實現(xiàn)一個隊列
protocol Queue {
    associatedtype Element // self持有的類型
    mutating func enquenue(_ element: Element) // 入隊
    mutating func dequenue() -> Element? // 出隊
}


struct FIFOQuenue<Element>: Queue {
    mutating func enquenue(_ element: Element) { // 入隊
        right.append(element)
    }


    mutating func dequenue() -> Element? { // 出隊
        if left.isEmpty {
            left = right.reversed()
            right.removeAll()
        }
        return left.popLast()
    }

    fileprivate var left: [Element] = []
    fileprivate var right: [Element] = []

}

// 實現(xiàn)了這些 就能滿足Collection協(xié)議了
extension FIFOQuenue: Collection {
    func index(after i: Int) -> Int {
        precondition(i < endIndex)
        return i + 1
    }

    subscript(position: Int) -> Element {
        precondition((0..<endIndex).contains(position), "Index out of bounds")
        if position <  left.endIndex {
            return left[left.count - position - 1]
        } else {
            return right[position - left.count]
        }
    }

    // 我們要實現(xiàn)的有
    public var startIndex: Int { return 0 }
    public var endIndex: Int { return left.count + right.count }

}


var q = FIFOQuenue<String>()

for x in ["1", "2", "f00", "3"] {
    q.enquenue(x)
}

for s in q {
    print(s)
}

q.count

// 擴展 新的協(xié)議

extension FIFOQuenue: ExpressibleByArrayLiteral {
    init(arrayLiteral elements: Element...) {
        self.init(left: elements.reversed(), right: [])
    }
    typealias ArrayLiteralElement = Element
}

var qq = [1,2,3]

for ss in qq {
    print(ss)
}
  1. 索引
    startIndex 是第一個元素位置
    endIndex 是最后一個元素之后的位置

通過索引訪問 subscript 是Collection定義的 它總是返回非可選值
索引失效,可能是指向了另一個元素 或者本身失效了 訪問可能導致崩潰

索引步進 index(after:)

實現(xiàn)一個單向鏈表 (非整數(shù)索引)

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

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

  • 集合類型: Swift,和其他現(xiàn)代編程語言一樣,有內(nèi)置的集合類型數(shù)組(Array)和字典(Dictionary),...
    小松樹先生閱讀 1,163評論 0 2
  • Swift 語言提供Arrays、Sets和Dictionaries三種基本的集合類型用來存儲集合數(shù)據(jù)。數(shù)組(Ar...
    窮人家的孩紙閱讀 657評論 3 2
  • Swift 語言提供Arrays、Sets和Dictionaries三種基本的集合類型用來存儲集合數(shù)據(jù)。數(shù)組(Ar...
    CDLOG閱讀 504評論 0 1
  • 前言 3月27號蘋果發(fā)布了Swift3.1,官方教程也更新到了3.1,查看更新記錄發(fā)現(xiàn)更新的內(nèi)容對之前的文章并沒有...
    BoomLee閱讀 3,254評論 0 4
  • Swift提供了三種基本集合類型:Arrays Sets Dictionaries用來儲存集合數(shù)據(jù),數(shù)組(Ar...
    edison0428閱讀 381評論 0 0

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