美文网首页
Swift进阶一:内建集合类型

Swift进阶一:内建集合类型

作者: Trigger_o | 来源:发表于2021-10-11 17:10 被阅读0次

1.在swift中,类(class)作为引用类型,类的实例其实不太应该被称为对象(object),就应该是实例.

2."==="用于判断两个变量是否引用同一个实例,需要用在class的实例上,"=="需要相应类型实现这个运算符函数.

3.swift中也有指针,比如withUnsafeMutablePointer.

4.如果把函数赋值给一个变量,或者作为函数的参数或者返回值,这样的函数叫做闭包,但是不仅是如此,即使是func定义的函数,只要包含了外部变量,它也是一个闭包.

5.所谓方法,就是定义在类或者协议中的函数,不是方法的函数可以叫做自由函数.

6.swift在runtime中的表现,函数分为静态派发和动态派发,自由函数和结构体里调用的方法是静态派发,编译器会直接将函数调用替换为函数内的代码;类和协议的方法可能是动态派发的,@objc的类或协议的方法使用objc_msgSend,普通的方法使用Selector.

7.swift通过继承,方法的复写(重写),重载(为同一个方法实现多种类型的实现),和泛型来实现多态.泛型的方法是静态的.

8.在swift中,集合类型被赋值给另一个变量时,数组的内容会被复制.作为参数专递给函数时,也是一样的.而OC的NSMutableArray等,需要手动copy.
这种频繁的复制并不会造成性能压力,swift中的集合类型都使用了"写时复制"的特性,在下面的例子中,append调用之前x和y是共用的同一份,写实复制也可以在自定义的类型中实现.


Array
NSMutableArray

9.swift为Array提供了很多OC没有的方法,并且移除了C风格的for循环语法,这是因为swift不鼓励索引计算;
first和last是可选值,removelast在数组为空是会crash,而popLast在数组为空时,什么都不做.


迭代方法

10.数组变形,swift提供了一系列Element方法
例如使用map来对元素进行变换,通过闭包,每个元素获得一个新元素,最终返回一个新数组.
map 可以将模板代码分离出来,这些模板代码并不会随着每次调用发生变动,发生变动的是那些功能代码,也就是如何变换每个元素的逻辑代码。map 函数通过接受调用者所提供的变换函数作为参数来做到这一点。


map应用
map应用

11.类似map的这种设计叫做函数行为参数化,在swift标准库中很多这样将行为进行参数化的设计模式.这些非常方便,例如排序people.sort { 0.age <1.age };是否包含满足某个条件的元素people.contains { $0.age < 18 };等等

image.png
image.png
image.png
这些方法都是这样的结构:
extension Array {
    func map<T>(_ transform: (Element) -> T) -> [T] {
        var result: [T] = []
        result.reserveCapacity(count)
        for x in self {
            result.append(transform(x))
        }
        return result
    }
}

据此,也可以自定义一些类似的方法.

12.map不一定是有序的,下面这段代码是创建了一个临时遍历runing,每个元素变成前面所有元素的和

extension Array {
    func accumulate<Result>(_ initialResult: Result, _ nextPartialResult: (Result, Element) -> Result) -> [Result]{
        var running = initialResult
        return map { next in
            running = nextPartialResult(running, next)
            return running
        }
    }
}
//调用
[1,2,3,4].accumulate(0, +) // [1, 3, 6, 10]

这里是假设map是按照下标0开始迭代,这样做不可靠,应该使用for循环更合理.

13.map 和 filter 都作用在一个数组上,并产生另一个新的、经过修改的数组。不过有时候,你可
能会想把所有元素合并为一个新的值。比如,要是我们想将元素的值全部加起来.


求和

使用reduce方法,0是起始值,后面是一个行为,也可以直接写成运算符方法

//        let sum = fibs.reduce(0) { partialResult, num in
//            partialResult + num
//        }
        let sum = fibs.reduce(0, +)

输出值的类型可以任意

        let sum2 = fibs.reduce("") { partialResult, num in
            partialResult + "\(num)"
        }

reduce的实现

extension Array {
    func reduce<Result>(_ initialResult: Result, _ nextPartialResult: (Result, Element) -> Result) -> Result {
        var result = initialResult
        for x in self {
            result = nextPartialResult(result, x)
        }
        return result
    }
}

14.compactMap相当于map加上filter

        let possibleNumbers = ["1", "2", "three", "///4///", "5"]
        let mapped: [Int?] = possibleNumbers.map { str in Int(str) }
        // [1, 2, nil, nil, 5]
        let compactMapped: [Int] = possibleNumbers.compactMap { str in Int(str) }
        // [1, 2, 5]

15.数组和字符串都有切片,切片是一种表示方式,数据仍然是原来的数组或者字符串

let fibs = [0,1,2,3]
let sli = fibs[1...]
let ff = Array(sli)

sli的类型是ArraySlice<Int>,这里的关键在于数组fibs并没有被复制,当调用第三行时,内容才被复制

16.合并字典 merge(_:uniquingKeysWith:),也是一个函数行为参数化的方法
合并首先会把key取并集,如果两个字典都存在某个key,通过行为参数设置选择左边的还是右边的.

        let defaultSettings: [String:Setting] = [ "Airplane Mode": .bool(false), "Name": .text("My iPhone")]
        var settings = defaultSettings
        let overriddenSettings: [String:Setting] = ["Name": .text("Jane's iPhone")]
        settings.merge(overriddenSettings) { _, key1 in
            key1
        }
//        settings.merge(overriddenSettings, uniquingKeysWith: { $1 })

17.字典是Sequence类型,因此它有一个map方法,返回一个数组,另外还有一个mapValue方法来处理每个值

        let dic = ["aa":1,"bb":2]
        let arr = dic.map({ $0.value })
        print(arr)//[2, 1]
        
        let dic2 = dic.mapValues { v in
            v * 2
        }
        print(dic2) //["bb": 4, "aa": 2]

18.关于Hashable
字典是哈希表,通过key的哈希值来指定它的位置,以及对应的存储,因此key的类型要遵循Hashable协议,基本类型字符串,整数,浮点数以及布尔值都遵循Hashable,如果想用非值类型来作为key,则需要手动遵循Hashable并实现hashValue和"=="运算符两个方法,相同的两个实例哈希值必须相同,反过来不一定;并且做这些的时候还需要考虑哈希值的计算效率以及回避哈希碰撞

19.set也是哈希表,相当于只存了key的字典,因此元素需要遵循Hashable,set遵循ExpressibleByArrayLiteral协议,可以用数组字面量赋值,

let naturals: Set = [1, 2, 3, 2]  //[2,1,3]

集合提供了一些数学意义上的方法在协议 SetAlgebra中,比如交集,并集,补集

//补集
let iPods: Set = ["iPod touch", "iPod nano", "iPod mini", "iPod shuffe", "iPod Classic"]
let discontinuedIPods: Set = ["iPod mini", "iPod Classic", "iPod nano", "iPod shuffe"]
let currentIPods = iPods.subtracting(discontinuedIPods) // ["iPod touch"]

//交集
let touchscreen: Set = ["iPhone", "iPad", "iPod touch", "iPod nano"]
let iPodsWithTouch = iPods.intersection(touchscreen)
// ["iPod touch", "iPod nano"]

//并集
var discontinued: Set = ["iBook", "Powerbook", "Power Mac"]
discontinued.formUnion(discontinuedIPods)
//["iBook", "Powerbook", "Power Mac", "iPod Classic", "iPod mini", "iPod shuffe", "iPod nano"] 

给Array 添加一个方法,实现有序集合去重

extension Array where Element : Hashable{
    func unique() -> [Element]{
        var seen : Set<Element> = []
        return filter { el in
            if seen.contains(el){
                return false
            }else{
                seen.insert(el)
                return true
            }
        }
    }
}

20.Range既非集合又非序列,因此不能迭代,但是却可以写出for i in 0..<10,这是因为 0..<10 的类型其实是一个 CountableRange<Int>类型,叫做可数范围,与Range不同,它的元素类型需要遵守Strideable 协议 (以整数为步⻓);
如果元素类型仅仅只是满足 Comparable,它对应的是“普通” 范围 (这是范围元素的最小要求),那些元素满足Strideable,并且使用整数作为步⻓的范围则是可数范围;只有后一种范围是集合类型.


区别

相关文章

网友评论

      本文标题:Swift进阶一:内建集合类型

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