美文网首页
swift-集合类型

swift-集合类型

作者: AlliumLiu | 来源:发表于2019-04-21 14:29 被阅读0次

数组

  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...<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
        }
    }
}
// 这样就可以合并字典了 而且参数可以是键值对数组或任意类似序列
  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<Wrapped> {
    case none
    case some(Wrapped)
}
  • 和岗哨值不通 除非显示的检测解包否则你不可能意外使用到一个Optional中的值
  • index(of:) 就会返回一个Optional<Index>的值 它遵守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<Optional<Int>> 系统会自动解包一层
  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<Optional<Int>>

let x = numbers.first.flatMap{ Int($0) } //Optional<Int>
  1. 比较 我们可以 写出代码 if numbers.first == "1" 而不需要加 Optional("1") 然而 [Int?] == [Int?] 是不可以的 因为 == 需要数组元素遵守Equable 协议
  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)\""
崩溃前执行
  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<Int> {
    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<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] = []

}

// 实现了这些 就能满足Collection协议了
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]
        }
    }

    // 我们要实现的有
    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

// 扩展 新的协议

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-集合类型

    简介 一组同类型的值的组合, 根据组合的整体特性分为: 有序可重复 - 数组(Array) 无序不重复 - Set...

  • Swift-集合类型

    前言 3月27号苹果发布了Swift3.1,官方教程也更新到了3.1,查看更新记录发现更新的内容对之前的文章并没有...

  • Swift-集合类型

    Swift提供了三种主要的集合类型,称为数组,集合和字典,用于存储值的集合。数组是值的有序集合。集是唯一值的无序集...

  • swift-集合类型

    数组 数组和可变性// 斐波那契数列let fibs = [0,1,1,2,3,5]不可变 不能用append(_...

  • Swift-存储类型-集合

    集合在集合中存储相同类型的不同值,没有定义的顺序。 当元素的顺序不重要时,或者当您需要确保元素只出现一次时,您可以...

  • Swift-基础、集合类型、控制流等

    最近项目使用的是OC,后头看之前用Swift开发的一个项目时,发现很多细节都忘记了??。为了回忆和以后方便查看,现...

  • Swift-集合

    集合的初始化 集合的成员变量 遍历 集合的增删改查 集合中的数学方法

  • MemoryLayout理解

    swift-指针类型Memory Layout的简介与使用 https://blog.csdn.net/die_w...

  • swift-集合Set

    集合特点: 无序的数据集 排重, 数据唯一 提供集合操作 快速查找 集合操作 集合操作 加上Inplace就会改变...

  • iOS 深拷贝浅拷贝

    一,集合类型(NSArray、NSDictionary、NSSet等类型)与非集合类型(NSString等类型) ...

网友评论

      本文标题:swift-集合类型

      本文链接:https://www.haomeiwen.com/subject/gexjgqtx.html