从Swift3开始写项目,将学到的知识点记录下来,作为笔记方便以后查阅与复习。
可变性
let numbers = [1, 2, 3, 4, 5]
如果使用append(_:)
这样的方法来修改上面定义的数组的话,会得到一个编译错误。这是因为在上面的代码中数组是用 let 声明为常量的,要让数组具有可变性,我们应该使用var来定义数组。
var numbers = [1, 2, 3, 4, 5]
numbers.append(8)
numbers.append(contentsOf: [13, 21])
numbers // [1, 2, 3, 4, 5, 8, 13, 21]
let定义的变量具有不可变性,应该被优先使用,不过仅仅只是针对值语义类型。用let定义的引用类型,只保证这个引用不可变,引用指向的对象是可以改变的,而Swift的数组属于值语义类型,后续写结构体与类再做详细介绍。
迭代
实际上Swift不建议开发者去手动操作索引,这样往往可能带来很多潜在的bug。所以从Swift3开始,传统C语言风格的循环被移除了。
for element in array // 基础迭代
for element in array.dropFirst() // 迭代除了第一个元素之外数组的其他部分
for element in array.dropLast(2) // 迭代除了最后两个元素之外数组的其他部分
for (index, element) in collection.enumerated() // 列举数组中对应的元素与下标
获取元素的索引,array.index系列函数
-
array.forEach {element in print(element)}
forEach
与第一个for in
循环区别不大。有个注意点就是当for
循环中有return
语句时,forEach
中的return
不能返回到外部函数的作用域,只能返回到闭包本身之外,例如:
let numbers = [1, 2, 3, 4, 5]
numbers.forEach { number in
debugPrint(number)
if number > 2 {return}
}
这段代码会输出全部的数字,return
语句不会终止循环。
高阶函数
-
Map
Swift数组的map
方法出自函数式编程,它会对数组的每一个元素变形,然后返回一个新的数组。例如将一个数组的所有元素平方,然后返回一个新的数组:
let numbers = [1, 2, 3, 4, 5]
let numMap = numbers.map {num in num * num}
// 还有更简便的写法
let numMap = numbers.map {$0 * $0}
-
Filter
filter
方法会遍历数组,将符合条件的元素过滤出来,放入新的数组并返回。
let numbers = [1, 2, 3, 4, 5]
let numFilter = numbers.filter {num in num % 2 == 0}
// 简写
let numFilter = numbers.filter {$0 % 2 == 0}
-
Reduce
reduce
方法可以把所有的元素合并处理,返回一个新的值,例如返回数组所有元素的和:
let numbers = [1, 2, 3, 4, 5]
let numReduce = numbers.reduce(0) { result, num in
return result + num
}
// Swift中运算符也是函数,因此可以简写
let numReduce = numbers.reduce(0, +)
// 还可以对数组的元素做其他的操作,返回不同类型的值,例如字符串
// ...
-
FlatMap
flatMap
方法一般用来进行复合数组的展平操作,这里不多做介绍了。
总结:可通过组合使用map与filter实现一些功能,感兴趣的可以去查找map、filter、reduce底层实现的相关资料。map与filter其实也可以用reduce来实现。
Swift标准库中,还有很多类似接收一个函数,将这个函数作为逻辑代码的方法,例如:
-
sort、lexicographicCompare、partition:
对元素进行排序 -
index、first、contains:
符合某个特定条件 -
min、max:
最小与最大值 -
elementsEqual:
元素是否相等 prefix
drop
切片
Swift的数组可根据索引范围来获取数组的范围,例如:
let numbers = [1, 2, 3, 4, 5]
let slice1 = numbers[2...]
let slice2 = numbers[...3]
上面的slice1与slice2类型为ArraySlice<Int>
,不是Array
。切片的数据共享原数组的数据,共享原数组的内存,不需要额外的复制开销,方法都是跟Array
一样的。将切片转为普通数组let arr = Array(slice1)
可选值注意点
-
first、last:
都返回可选值类型,数组为空时返回nil。实现类似于isEmpty ? nil : element
-
removeLast:
数组为空会导致崩溃,不为空时则移除最后一个元素 -
popLast:
数组为空时返回nil,不为空时删除最后一个元素返回它