每天了解一点不一样的 Swift 小知识
代码截图
小笔记
为什么只用传递一个 <
就实现了功能
与 Objective-C 不同的是,<
在 Swift 中是一个独立的函数,与其他的函数一样,类似 <
这样的操作符也拥有函数参数和函数返回值。
我们看一下 <
的定义
它其实本质就是一个返回值为 (lhs: Self, rhs: Self) -> Bool
的函数,所以将今天的代码进行如下改造:
1 | let ascending: (Int, Int) -> Bool = { (lhs, rhs) -> Bool in |
这段代码里 ascending 扮演的功能与 <
完全一样,只是用了一个更容易理解的方式写代码。
当然你也可以这么理解 <
1 | let sorted = array.sorted(by: { (lhs, rhs) -> Bool in |
这种把函数当做入参的方式,在 Swift 的一些高阶函数使用中经常可以遇到,应该是需要了解的一个知识点。
这里推两篇拓展阅读:HIGHER-ORDER FUNCTIONS IN SWIFT 和 Swift Guide to Map Filter Reduce
我好像还看到过 array.sorted{ $0 < $1 }
的写法
array.sorted{ $0 < $1 }
和 array.sorted(by: <)
本质上没有任何区别,即运算结果一致,只是利用了不同的 Swift 语言特性,使其在最终的展示层面出现了一些变化。
这里我们来分析下代码是如何一步步变成 array.sorted{ $0 < $1 }
的。其中涉及的知识点主要有 4 个
- 隐式返回函数
- 尾随闭包
- 类型推断
- 参数名称缩写
sorted 最原始的代码形式应该是这样的:
1 | let sortedA = array.sorted(by: { (lhs, rhs) -> Bool in |
隐式返回的函数
隐式返回的函数是指:如果一个函数的整个函数体是一个单行表达式,那么就可以隐式地返回这个表达式,也就是说我们可以省略像 return
这样的关键字。
结合原始代码的实际情况,它将变成如下的形式:
1 | let sortedB = array.sorted(by: { (lhs, rhs) -> Bool in |
尾随闭包
尾随闭包是一个书写在函数圆括号之后的闭包表达式,函数支持将其作为最后一个参数调用。在使用尾随闭包时,你不用写出它的参数标签。
结合上面的代码,我们可以将其转换为如下的形式:
1 | let sortedC = array.sorted(){ (lhs, rhs) -> Bool in |
不过这还不最简洁的,如果闭包参数是传给函数的唯一参数,你还可以完全忽略括号。
1 | let sortedD = array.sorted{ (lhs, rhs) -> Bool in |
类型推断
凭借着 Swift 强大的类型推断能力,上面的代码在还可以进一步简化成如下的形式。
1 | let sortedE = array.sorted{ lhs, rhs in lhs > rhs } |
参数名称缩写
在 Swift 中,可以通过参数名称缩写而不是参数名字来引用参数
如果在闭包表达式中使用参数名称缩写,就可以在闭包定义中省略参数列表,并且对应参数名称缩写的类型会通过函数类型进行推断。in
关键字也同样可以被省略,此时闭包表达式完全由闭包函数体构成:
1 | let sortedF = array.sorted{ $0 > $1 } |
拓展阅读: Shorthand Argument Names in Swift
最后说点什么?
Swift 的这些特性使其可以写出十分简洁的代码,让很多程序员爱不释手,但有时候过多的”美化”,反而增加了一些阅读门槛。
这里不妨举 2 个例子
1 | let value: Int? = 1 |
在这里,map 函数被用来处理可选值。
1 | // Solution A |
而这里利用了参数名称缩写的方式来简化闭包内部的实现。
以上代码到底是 Solution A 好还是 Solution B 好,我确实无法给出一个完美的答案,所以如何写出一份让所有人都觉得阅读体验良好的代码,或许会成为 Swifter 开发者甜蜜的烦恼吧。