由于 Swift 不再支持宏了,于是 MAX,MIN 等一些列常用宏都被重写为 Swift 函数。我们来看看函数的定义:
1 |
|
warn_unused_result
先说说 @warn_unused_result 注解。 顾名思义,被该注解标记的方法所产生的返回值,如果未被使用,编译器会不开心哦(编译的时候会产生一条警告⚠️)。
这里讲一下方法的设计哲学。一般来说一个理想的带有返回值的方法,除了返回返回值以外,是不会产生任何其他副作用的。比如说不会改变入参的值(这也是 inout
存在的原因)
,不会对系统的其他状态有影响(比如说不会改变类的实例变量的值)。这样的好处是减少方法产生的不确定性,同时方法使用的目的变得非常明确。
拿 max
来举例。max
方法被设计用来判断并返回两个参数中更大的那个。容易理解,当返回值没有被使用的时候,这次方法的调用也是没有意义的,因此 @warn_unused_result 的标注是非常合理的。
所以当你在开发 SDK 或是框架,甚至是和同事合作开发业务,同事会用到你的 API 的时候,你可以在需要的地方,用此注解来标记你的方法,以提示使用者注意使用方法产生的返回值。
面向协议
从方法的定义中,我们可以看到,传入的参数只要符合 Comparable
协议,就可以正确得到返回结果。
这意味着我们不仅可以用它来比较数字大小:
1 | let maxInteger = max(10, 20) |
还可以用来比较 String
的大小
1 | let maxString = max("bc", "abc") |
甚至是自定义的对象,只要它实现了 Comparable
协议。从这一点上,我们可以窥见 Swift “面向协议编程” 的一斑。面向协议编程让 max(_:_:)
从具体的类中解放出来,不关心入参是什么类,有什么结构,只关心 所传进来的参数能否被比较,而具体的比较则让入参自己去做,从而让 max(_:_:)
具有普适性,达到程序设计上的低耦合。
这么说可能有点抽象,我们来举个具体的例子。
假设我们有这样的餐馆定义
1 | struct Restaurant { |
如何比较两家餐馆谁大谁小?
按照餐馆面积比,平海路上的日料店表示不服;按照人均消费比,新白鹿表示不服;按照米其林等级比,一众特色小吃店表示不服;按照餐厅名称长度比,产品经理表示不服。
总地来说,”谁更大”其实是一种抽象的概念, max
方法不能也不该知道入参是如何比较的。只有入参自己知道自己该如何比较。因此抽象出 Comparable
协议是非常自然的。
Comparable
我们再来看看 Comparable
的定义
1 | public protocol Comparable : Equatable { |
Comparable
抽象了数学上严格全序的概念。虽然定义了五个方法(别忘了 Equatable 中还有一个 ==),但只需要实现 ==
和 <
,其他方法只需要使用 Swift 标准库提供的默认实现,就可以根据严格全序定义推导出实现。
数学真是计算机科学的基石啊!