swift-集合类型

数组

  1. 数组和可变性
    // 斐波那契数列
    let fibs = [0,1,1,2,3,5]
    不可变 不能用append(_:)
    var fibs = [0,1,1,2,3,5]
let 只能保证引用永远不发生变化,而不能保证引用的值发生变化
标准库里的集合类型都是有值语义的
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. 数组和可选值
    标准库的提供的 first last popLast 不会数组越界 而是 返回 Optional 它总会执行边界检查
  2. Map Filter ....
  3. 数组切片
    数组切片不是Array,只是数组的一种表示方式,但是可以当做Array使用
let slice = fibs[1...

字典

字典是无序的,字典是一种稀疏结构不能保证某个键下的值是否有值

  1. 可变性
  2. 扩展merge
extension Dictionary {
    mutating func merge(_ other: S) where S: Sequence, S.Iterator.Element == (key: Key, value: Value) {
        for (k, v) in other {
            self[k] = v
        }
    }
}
// 这样就可以合并字典了 而且参数可以是键值对数组或任意类似序列
  1. Hashable 要求
    字典其实是哈希表,字典通过键 hashValue 来确定值的位置
    标准库中所有类型都支持 Hashable 要求

Set

无序且不重复

  1. 执行集合代数 SetAlgebra 协议
    Set 是标准库中唯一实现了 SetAlgebra 协议的类型,而Foundation中有另外的IndexSet,CharacterSet 他们已经被Swift以值的方式导入了

Range

范围代表两个值之间的区域let singleDigitNumbers = 0..<10, let lowercaseLetters = Character('a')...Character('z')
范围看起来是一个序列或集合类型,但它并非两者之一。

     | 半开范围 | 闭合范围

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

以整数为步长

  • 只有半开范围能表达空间区的概念
  • 只有闭合范围能包含元素类型的最大值 0...Int.max 半开范围总是最少有一个值比范围所表达的值要大 Int.max + 1 ???
  • 只有那些可数的区域才能 for in 遵循Sequence协议

集合类型协议 太难下次再讲

可选值

  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 最为常见
  • 函数返回一个代表并没有返回真实的值的值,被称为 岗哨值
  • 它容易被忽略检测而产生错误
let s: NSString? = "..."
if s.range(of: "swift").location != NSNotFound {
    print("someone mentioned sift!")
}

如果someString 是 nil 将返回一个都是0的range 语句将会被执行

  1. 通过枚举解决问题 swift 的枚举可包含另外的关联值
enum Optional {
    case none
    case some(Wrapped)
}
  • 和岗哨值不通 除非显示的检测解包否则你不可能意外使用到一个Optional中的值
  • index(of:) 就会返回一个Optional的值 它遵守ExpressibleByNilLiteral协议 可以写作 Index? 用 nil 代替.none
  • 如果你要使用返回的值 就必须解包
  1. if let
  2. while let
    在 Swift 中 for in 其实就是 where let 来实现的 避免了闭包的值捕获问题
a = []
for i in 1..3 {
        a.push(lambda{i})
}

for f in a {
        print "#{f.call()}"
}
输出 ???
  1. 双重可选值 Optional> 系统会自动解包一层
  2. if var and while var
  3. guard 可以 扩大 可选作用域
  4. 可选链 OC 中nil 不会发消息 执行方法 swift中 ?可选链实现了同样的效果
  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>

let x = numbers.first.flatMap{ Int($0) } //Optional
  1. 比较 我们可以 写出代码 if numbers.first == "1" 而不需要加 Optional("1") 然而 [Int?] == [Int?] 是不可以的 因为 == 需要数组元素遵守Equable 协议
  2. 改进强制解包错误信息
func !! (wrapped: T?, failureText: @autoclosure ()-> String) -> T {
    if let x = wrapped {
        return x
    }
    fatalError(failureText())
}
let ss = "foo"
let i = Int(ss) !! "nonono, get \"\(ss)\""
崩溃前执行
  1. 隐式可选值
var s: String! = "s"

在行为上它表现的像是非可选值,但它还可以使用可选值 的可选链 if let 等

集合类型协议

在之前,我们看到了 Array Dictionary 和 Set,它们并非空中楼阁,而是建立在一系列由 Swift 标准库提供的用于处理元素序列的抽象之上的。
Sequence 和 collection协议,它们构成了这套集合类型模型的基石。本章会研究这些协议是如何工作的,它们为什么要以这样的方式工作,以及如何写出自己的序列和集合类型等
  1. 序列
    Sequence协议是集合序列的基础,代表的是一系列具有相同类型的值,你可以对这些值进行迭代。遍历一个序列最简单的方式是使用for循环
for element in someSequence {
doSomething(with: element)
}

Sequence协议提供了许多强大的功能,满足该协议的类型都可以直接使用这些功能。上面这样步进式地迭代元素的能力看起来十分简单,但它却是 Sequence可以提供这些强大功能的基础。在上一章中已经提到过不少这类功能了,每当你遇到一个能够针对元素序列进行的通用的操作,你都应该考虑将它实现在 Sequence层可能性。在接下来的部分,会看到许多这方面的例子。
满足 Sequence 协议非常简单 只需要提供一个返回迭代器iteratormakeIterator()方法:

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

对于迭代器,我们现在只能从 Sequence 的定于中看出他满足 IteratorProtocol协议的类型。所以首先来仔细看看迭代器是什么。

  1. 迭代器
    序列通过一个迭代器来访问元素 IteratorProtocol 协议中有一个next()方法返回序列中下一个元素的值直到序列耗尽返回 nil
protocol IteratorProtocol {
        associatedtype Element
        mutating func next() -> Element?
}
本质上for循环就是下面代码的简写 当然我们也可创造无限序列
var iterator = someSequence.makeIterator()
while let element = iterator.next() {
    doSomething(with: element)
}

next 被标记mutating 看起来是不需要的 但实践中迭代器本质是存在状态的

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
    }
}

基于函数的迭代器序列

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

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

无限序列, sequence 的 next 闭包总是延时执行的 也就是说 下一个next 不会被自动计算 prodiver.prefix(10) 只会求前10个
如果序列主动计算 它就会溢出崩溃
对集合和序列来说 区别之一 就是 序列可以无限 而集合不行

不稳定序列 网络流 UI时间流 磁盘文件 都可以用序列建模
网络包这种序列将被遍历消耗再次遍历不能保证是同样的值,
sequence 明确指出了不保证可以被多次遍历

  1. 集合类型 Collection

是指那些稳定的序列 能够被多次遍历并保存一致,可以下标访问 有起始和终止索引。

Collection协议是基于Sequence来的除了继承所有方法外,它还可以获取指定位置的元素 获取 稳定的迭代的保证,count等新的特性

  1. (1)实现一个队列 (2)遵守ExpressibleByArrayLiteral 协议 (3)关联类型
// 实现一个队列
protocol Queue {
    associatedtype Element // self持有的类型
    mutating func enquenue(_ element: Element) // 入队
    mutating func dequenue() -> Element? // 出队
}


struct FIFOQuenue: 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] = []

}

// 实现了这些 就能满足Collection协议了
extension FIFOQuenue: Collection {
    func index(after i: Int) -> Int {
        precondition(i < endIndex)
        return i + 1
    }

    subscript(position: Int) -> Element {
        precondition((0..()

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

for s in q {
    print(s)
}

q.count

// 扩展 新的协议

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:)

实现一个单向链表 (非整数索引)

你可能感兴趣的:(swift-集合类型)