swift 学习笔记2

来源:互联网 发布:sql server下载 编辑:程序博客网 时间:2024/06/16 18:12



1.闭包的简介

看到这里, 或许有人想着, 又是一个新的东西, 其实不以为然, 所谓的闭包其实就是OC中block, 只是在block的基础上做出了稍微的改变, 但最终的原理和block八九不离十, 闭包除去可以使用类似block的原理之外, 还多了一些特性, 比如闭包可以捕获和存储其所在上下文中任意常量和变量的引用。 这就是所谓的闭合并包裹着 这些常量和变量,俗称闭包.

其实闭包我们在函数的章节中也讲过, 全局和嵌套函数实际上是特殊的闭包, 而闭包是有三种不同的形态: 
1. 全局函数是一个有名字但不会捕获任何值的闭包 
2. 嵌套函数是一个有名字并可以捕获其封闭函数域内值的闭包 
3. 闭包表达式是一个利用轻量级语法所写的可以捕获其上下文中变量或常量值的没有名字的闭包

PS: 关于捕获这个概念, 后面会去慢慢讲解


2.闭包的表达式

嵌套函数是一种在较复杂函数中方便进行命名和定义自包含代码模块的方式, 当然, 有时候撰写小巧的没有完整定义和命名的类函数结构也是很有用处的, 尤其是在处理一些函数并需要将另外一些函数作为该函数的参数时.

闭包表达式是一种利用简洁语法构建内联闭包的方式. 闭包表达式提供了一些语法优化, 使得撰写闭包变得简单明了.


3.Sorted函数

Swift 标准库提供了sorted函数, 会根据您提供的排序闭包将已知类型数组中的值进行排序, 一旦排序完成, 函数会返回一个与原数组大小相同的新数组, 该数组中包含已经正确排序的同类型元素, 比如:

<code class="hljs javascript has-numbering" style="display: block; padding: 0px; background-color: transparent; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal;"><span class="hljs-keyword" style="box-sizing: border-box;">let</span> names = [<span class="hljs-string" style="box-sizing: border-box;">"Chris"</span>, <span class="hljs-string" style="box-sizing: border-box;">"Alex"</span>, <span class="hljs-string" style="box-sizing: border-box;">"Ewa"</span>, <span class="hljs-string" style="box-sizing: border-box;">"Barry"</span>, <span class="hljs-string" style="box-sizing: border-box;">"Daniella"</span>]func backwards(s1: <span class="hljs-built_in" style="box-sizing: border-box;">String</span>, s2: <span class="hljs-built_in" style="box-sizing: border-box;">String</span>) -> Bool {    <span class="hljs-keyword" style="box-sizing: border-box;">return</span> s1 > s2}<span class="hljs-keyword" style="box-sizing: border-box;">var</span> reversed = sorted(names, backwards)println(reversed)<span class="hljs-comment" style="box-sizing: border-box;">// 打印出来的结果: [Ewa, Daniella, Chris, Barry, Alex]</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li></ul>

PS: 其实我们是可以理解成为一个数组提供了排序的方法, 根据backwards函数里的两个形参判断, 是否返回true, 如果是的话, s1就放在s2之前, 依此类推, 所以打印出来的结果就和上面的例子一样.


4.闭包的表达式语法

闭包表达式语法可以使用常量, 变量和 inout 类型作为参数,但不提供默认值。 也可以在参数列表的最后使用可变参数, 元组也可以作为参数和返回值, 比如:

<code class="hljs javascript has-numbering" style="display: block; padding: 0px; background-color: transparent; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal;">reversed = sorted(names, {(s1: <span class="hljs-built_in" style="box-sizing: border-box;">String</span>, s2: <span class="hljs-built_in" style="box-sizing: border-box;">String</span>) -> Bool <span class="hljs-keyword" style="box-sizing: border-box;">in</span> <span class="hljs-keyword" style="box-sizing: border-box;">return</span> s1 > s2 })<span class="hljs-keyword" style="box-sizing: border-box;">let</span> name = [<span class="hljs-string" style="box-sizing: border-box;">"a"</span>, <span class="hljs-string" style="box-sizing: border-box;">"b"</span>, <span class="hljs-string" style="box-sizing: border-box;">"c"</span>, <span class="hljs-string" style="box-sizing: border-box;">"d"</span>, <span class="hljs-string" style="box-sizing: border-box;">"e"</span>, <span class="hljs-string" style="box-sizing: border-box;">"f"</span>, <span class="hljs-string" style="box-sizing: border-box;">"g"</span>]<span class="hljs-keyword" style="box-sizing: border-box;">var</span> a = reverse(name)println(a)<span class="hljs-comment" style="box-sizing: border-box;">// 打印出来的结果: [g, f, e, d, c, b, a]</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li></ul>

PS: 需要注意的是内联闭包参数和返回值类型声明与 backwards 函数类型声明相同, 在这两种方式中,都写成了 (s1: String, s2: String) -> Bool 类型, 然而在内联闭包表达式中, 函 数和返回值类型都写在大括号内,而不是大括号外, 闭包的函数体部分由关键字 in 引入, 该关键字表示闭包的参数和返回值类型定义已经完成, 闭包函数体即将开始.


5.根据上下文推断类型

因为排序闭包是作为函数的参数进行传入的,Swift 可以推断其参数和返回值的类型, 比如:

<code class="hljs javascript has-numbering" style="display: block; padding: 0px; background-color: transparent; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal;"><span class="hljs-keyword" style="box-sizing: border-box;">let</span> names = [<span class="hljs-string" style="box-sizing: border-box;">"Chris"</span>, <span class="hljs-string" style="box-sizing: border-box;">"Alex"</span>, <span class="hljs-string" style="box-sizing: border-box;">"Ewa"</span>, <span class="hljs-string" style="box-sizing: border-box;">"Barry"</span>, <span class="hljs-string" style="box-sizing: border-box;">"Daniella"</span>]func backwards(s1: <span class="hljs-built_in" style="box-sizing: border-box;">String</span>, s2: <span class="hljs-built_in" style="box-sizing: border-box;">String</span>) -> Bool {    <span class="hljs-keyword" style="box-sizing: border-box;">return</span> s1 > s2}reversed = sorted(names, { s1, s2 <span class="hljs-keyword" style="box-sizing: border-box;">in</span> <span class="hljs-keyword" style="box-sizing: border-box;">return</span> s1 > s2 } )println(reversed)<span class="hljs-comment" style="box-sizing: border-box;">// 打印出来的结果: [Ewa, Daniella, Chris, Barry, Alex]</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li></ul>

在单行闭包的时候, 我们可以不加return, 比如:

<code class="hljs javascript has-numbering" style="display: block; padding: 0px; background-color: transparent; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal;"><span class="hljs-keyword" style="box-sizing: border-box;">let</span> names = [<span class="hljs-string" style="box-sizing: border-box;">"Chris"</span>, <span class="hljs-string" style="box-sizing: border-box;">"Alex"</span>, <span class="hljs-string" style="box-sizing: border-box;">"Ewa"</span>, <span class="hljs-string" style="box-sizing: border-box;">"Barry"</span>, <span class="hljs-string" style="box-sizing: border-box;">"Daniella"</span>]func backwards(s1: <span class="hljs-built_in" style="box-sizing: border-box;">String</span>, s2: <span class="hljs-built_in" style="box-sizing: border-box;">String</span>) -> Bool {    <span class="hljs-keyword" style="box-sizing: border-box;">return</span> s1 > s2}reversed = sorted(names, { s1, s2 <span class="hljs-keyword" style="box-sizing: border-box;">in</span> s1 < s2 } )println(reversed)<span class="hljs-comment" style="box-sizing: border-box;">// 打印出来的结果: [Alex, Barry, Chris, Daniella, Ewa]</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li></ul>

PS: 实际上任何情况下, 通过内联闭包表达式构造的闭包作为参数传递给函数时, 都可以推断出闭包的参数和返回值类型, 这意味着您几乎不需要利用完整格式构造任何内联闭包,而且在单行闭包时, 我们还可以省略return这个关键字.


6.参数的简写

在闭包当中, 其实参数我们还有另外一种写法, 而且是非常的简单, 那就是用( $0, 1, 2)来代替, 比如:

<code class="hljs javascript has-numbering" style="display: block; padding: 0px; background-color: transparent; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal;"><span class="hljs-keyword" style="box-sizing: border-box;">let</span> names = [<span class="hljs-string" style="box-sizing: border-box;">"Chris"</span>, <span class="hljs-string" style="box-sizing: border-box;">"Alex"</span>, <span class="hljs-string" style="box-sizing: border-box;">"Ewa"</span>, <span class="hljs-string" style="box-sizing: border-box;">"Barry"</span>, <span class="hljs-string" style="box-sizing: border-box;">"Daniella"</span>]func backwards(s1: <span class="hljs-built_in" style="box-sizing: border-box;">String</span>, s2: <span class="hljs-built_in" style="box-sizing: border-box;">String</span>) -> Bool {    <span class="hljs-keyword" style="box-sizing: border-box;">return</span> s1 > s2}<span class="hljs-keyword" style="box-sizing: border-box;">var</span> reversed = sorted(names, {$<span class="hljs-number" style="box-sizing: border-box;">0</span> < $<span class="hljs-number" style="box-sizing: border-box;">1</span>})println(reversed)<span class="hljs-comment" style="box-sizing: border-box;">// 打印出来的结果: [Alex, Barry, Chris, Daniella, Ewa]</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li></ul>

PS: 这里面的($0, 1), 其实对应的就是闭包中的 s1 还有 s2.




1.Trailing闭包

在前面我们知道了简单的闭包是怎么样运用的, 但在实际开发中, 我们不可能只使用简单的闭包, 所以这时候就出现了第二种闭包的写法, 那就是Trailing闭包, 让我们来看看例子:

<code class="hljs coffeescript has-numbering" style="display: block; padding: 0px; background-color: transparent; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal;"><span class="hljs-reserved" style="box-sizing: border-box;">let</span> digitNames = [    <span class="hljs-number" style="box-sizing: border-box;">0</span>: <span class="hljs-string" style="box-sizing: border-box;">"Zero"</span>, <span class="hljs-number" style="box-sizing: border-box;">1</span>: <span class="hljs-string" style="box-sizing: border-box;">"One"</span>, <span class="hljs-number" style="box-sizing: border-box;">2</span>: <span class="hljs-string" style="box-sizing: border-box;">"Two"</span>, <span class="hljs-number" style="box-sizing: border-box;">3</span>: <span class="hljs-string" style="box-sizing: border-box;">"Three"</span>, <span class="hljs-number" style="box-sizing: border-box;">4</span>: <span class="hljs-string" style="box-sizing: border-box;">"Four"</span>,    <span class="hljs-number" style="box-sizing: border-box;">5</span>: <span class="hljs-string" style="box-sizing: border-box;">"Five"</span>, <span class="hljs-number" style="box-sizing: border-box;">6</span>: <span class="hljs-string" style="box-sizing: border-box;">"Six"</span>, <span class="hljs-number" style="box-sizing: border-box;">7</span>: <span class="hljs-string" style="box-sizing: border-box;">"Seven"</span>, <span class="hljs-number" style="box-sizing: border-box;">8</span>: <span class="hljs-string" style="box-sizing: border-box;">"Eight"</span>, <span class="hljs-number" style="box-sizing: border-box;">9</span>: <span class="hljs-string" style="box-sizing: border-box;">"Nine"</span>]<span class="hljs-reserved" style="box-sizing: border-box;">let</span> numbers = [<span class="hljs-number" style="box-sizing: border-box;">16</span>, <span class="hljs-number" style="box-sizing: border-box;">58</span>, <span class="hljs-number" style="box-sizing: border-box;">510</span>]<span class="hljs-reserved" style="box-sizing: border-box;">let</span> strings = numbers.map {    <span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-params" style="box-sizing: border-box;">(<span class="hljs-reserved" style="box-sizing: border-box;">var</span> number)</span> -></span> String <span class="hljs-keyword" style="box-sizing: border-box;">in</span>    <span class="hljs-reserved" style="box-sizing: border-box;">var</span> output = <span class="hljs-string" style="box-sizing: border-box;">""</span>    <span class="hljs-keyword" style="box-sizing: border-box;">while</span> number > <span class="hljs-number" style="box-sizing: border-box;">0</span> {        output = digitNames[number % <span class="hljs-number" style="box-sizing: border-box;">10</span>]! + output        number /= <span class="hljs-number" style="box-sizing: border-box;">10</span>    }    <span class="hljs-keyword" style="box-sizing: border-box;">return</span> output}println(strings)<span class="hljs-regexp" style="box-sizing: border-box;">//</span> 打印出来的结果: [OneSix, FiveEight, FiveOneZero]</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li></ul>

PS:  
1.在这个例子中, strings 常量被推断为字符串类型数组,即 [String], map 在数组中为每一个元素调用了闭包表达式, 您不需要指定闭包的输入参数 number 的类型,因为可以通过要映射的数组类型进行推断, 闭包表达式在每次被调用的时候创建了一个字符串并返回。其使用求余运算符 (number %10) 计算最后一位数字并利用 digitNames 字典获取所映射的字符串.

2.字典 digitNames 下标后跟着一个叹号 (!), 因为字典下标返回一个可选值 (optional value), 表明即使该 key 不存在也不会查找失败, 在上例中, 它保证了 number % 10 可以总是作为一个 digitNames 字典的有效下标 key, 因此叹号可以用于强展开 (force-unwrap) 存储在可选下标项中的 String 类型值.


2.捕获

在我们使用闭包的时候, 其实我们还可以捕获我们自己定义的常量或者变量, 即使里面的常量和变量的作用域不存在, 闭包仍然可以在闭包函数体内引用或者修改, Swift 最简单的闭包形式是嵌套函数,也就是定义在其他函数体内的函数, 嵌套函数可以捕 获其外部函数所有的参数以及定义的常量和变量, 让我们一起来看看:

<code class="hljs coffeescript has-numbering" style="display: block; padding: 0px; background-color: transparent; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal;">func makeIncrementor<span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-params" style="box-sizing: border-box;">(forIncrement amount: Int)</span> -></span> <span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-params" style="box-sizing: border-box;">()</span> -></span> Int {    <span class="hljs-reserved" style="box-sizing: border-box;">var</span> runningTotal = <span class="hljs-number" style="box-sizing: border-box;">0</span>    func incrementor<span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-params" style="box-sizing: border-box;">()</span> -></span> Int {        runningTotal += amount        <span class="hljs-keyword" style="box-sizing: border-box;">return</span> runningTotal    }    <span class="hljs-keyword" style="box-sizing: border-box;">return</span> incrementor}<span class="hljs-reserved" style="box-sizing: border-box;">let</span> incrementBySeven = makeIncrementor(<span class="hljs-attribute" style="box-sizing: border-box;">forIncrement</span>: <span class="hljs-number" style="box-sizing: border-box;">7</span>)<span class="hljs-reserved" style="box-sizing: border-box;">let</span> a = incrementBySeven()println(a)<span class="hljs-regexp" style="box-sizing: border-box;">//</span> 打印出来的结果: <span class="hljs-number" style="box-sizing: border-box;">7</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li></ul>

PS: 
1.makeIncrementor 返回类型为 () -> Int, 这意味着其返回的是一个函数,而不是一个简单类型值, 该函数在每次调用时不接受参数只返回一个 Int 类型的值, 关于函数返回其他函 数的内容,请查看 Function Types as Return Types.

2.makeIncrementor 函数定义了一个整型变量 runningTotal (初始为 0) 用来存储当前增加总数, 该值通过 incrementor 返回.

3.makeIncrementor 有一个 Int 类型的参数, 其外部命名为 forIncrement, 内部命名为 amount, 表示每次 incrementor 被调用时 runningTotal 将要增加的量.

4.incrementor 函数用来执行实际的增加操作, 该函数简单地使 runningTotal 增加 amount, 并将其返回.

5.Swift 会决定捕获引用还是拷贝值, 您不需要标注 amount 或者 runningTotal 来声明在嵌入的 incrementor 函数中的使用方式, Swift 同时也处理 runingTotal 变量的内存管理操作, 如果不再被 incrementor 函数使用, 则会被清除.

还有另外一个例子也很好玩, 比如:

<code class="hljs bash has-numbering" style="display: block; padding: 0px; background-color: transparent; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal;"><span class="hljs-built_in" style="box-sizing: border-box;">let</span> incrementBySeven = makeIncrementor(<span class="hljs-keyword" style="box-sizing: border-box;">for</span>Increment: <span class="hljs-number" style="box-sizing: border-box;">7</span>)<span class="hljs-built_in" style="box-sizing: border-box;">let</span> a = incrementBySeven()<span class="hljs-built_in" style="box-sizing: border-box;">let</span> b = incrementBySeven()<span class="hljs-built_in" style="box-sizing: border-box;">let</span> c = incrementBySeven()println(<span class="hljs-string" style="box-sizing: border-box;">"\(a), \(b), \(c)"</span>)// 打印出来的结果: <span class="hljs-number" style="box-sizing: border-box;">7</span>, <span class="hljs-number" style="box-sizing: border-box;">14</span>, <span class="hljs-number" style="box-sizing: border-box;">21</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li></ul>

上面已经很好的解释了, 这里我就不多做解释了, 还有一个注意点, 比如:

<code class="hljs bash has-numbering" style="display: block; padding: 0px; background-color: transparent; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal;"><span class="hljs-built_in" style="box-sizing: border-box;">let</span> incrementBySeven = makeIncrementor(<span class="hljs-keyword" style="box-sizing: border-box;">for</span>Increment: <span class="hljs-number" style="box-sizing: border-box;">7</span>)<span class="hljs-built_in" style="box-sizing: border-box;">let</span> a = incrementBySeven()<span class="hljs-built_in" style="box-sizing: border-box;">let</span> b = incrementBySeven()<span class="hljs-built_in" style="box-sizing: border-box;">let</span> c = incrementBySeven()println(<span class="hljs-string" style="box-sizing: border-box;">"\(a), \(b), \(c)"</span>)// 打印出来的结果: <span class="hljs-number" style="box-sizing: border-box;">7</span>, <span class="hljs-number" style="box-sizing: border-box;">14</span>, <span class="hljs-number" style="box-sizing: border-box;">21</span><span class="hljs-built_in" style="box-sizing: border-box;">let</span> incrementByTen = makeIncrementor(<span class="hljs-keyword" style="box-sizing: border-box;">for</span>Increment: <span class="hljs-number" style="box-sizing: border-box;">10</span>)<span class="hljs-built_in" style="box-sizing: border-box;">let</span> A = incrementByTen()<span class="hljs-built_in" style="box-sizing: border-box;">let</span> B = incrementByTen()<span class="hljs-built_in" style="box-sizing: border-box;">let</span> C = incrementByTen()println(<span class="hljs-string" style="box-sizing: border-box;">"\(A), \(B), \(C)"</span>)// 打印出来的结果: <span class="hljs-number" style="box-sizing: border-box;">10</span>, <span class="hljs-number" style="box-sizing: border-box;">20</span>, <span class="hljs-number" style="box-sizing: border-box;">30</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li></ul>

虽然这两个常量调用的是同一个闭包, 但是它们之间所捕获的内容并没有关联, 这个需要注意.


3.闭包是引用类型

 
上面的例子中, incrementBySeven 和 incrementByTen 是常量, 但是这些常量指向的闭包仍然可以增加其捕获的变量值. 这是因为函数和闭包都是引用类型.

无论您将函数/闭包赋值给一个常量还是变量, 您实际上都是将常量/变量的值设置为对应函数/闭包的引用, 上面的例子中, incrementByTen 指向闭包的引用是一个常量, 而并非闭包内容本身, 比如:

<code class="hljs cs has-numbering" style="display: block; padding: 0px; background-color: transparent; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal;"><span class="hljs-keyword" style="box-sizing: border-box;">let</span> alsoIncrementByTen = incrementByTen()println(alsoIncrementByTen)<span class="hljs-comment" style="box-sizing: border-box;">// 打印出来的结果: 40</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li></ul>

在Swift中有两种属性, 一种是计算属性, 另一种是存储属性, 计算属性可以用于类、结构体和枚举里,存储属性只能用于类和结构体, 让我们一起来看看吧:


1.存储属性

简单来说,一个存储属性就是存储在特定类或结构体的实例里的一个常量或变量,存储属性可以是变量存储属性(用关键字 var 定义),也可以是常量存储属性(用关键字 let 定义)。

可以在定义存储属性的时候指定默认值, 也可以在构造过程中设置或修改存储属性的值,甚至修改常量存储属性的值, 比如:

<code class="hljs go has-numbering" style="display: block; padding: 0px; background-color: transparent; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal;"><span class="hljs-keyword" style="box-sizing: border-box;">struct</span> FixedLengthRange {    <span class="hljs-keyword" style="box-sizing: border-box;">var</span> firstValue: Int    let length: Int}<span class="hljs-keyword" style="box-sizing: border-box;">var</span> rangeOfThreeItems = FixedLengthRange(firstValue:<span class="hljs-number" style="box-sizing: border-box;"> 0</span>, length:<span class="hljs-number" style="box-sizing: border-box;"> 3</span>)<span class="hljs-comment" style="box-sizing: border-box;">// 该区间表示整数0, 1, 2</span><span class="hljs-built_in" style="box-sizing: border-box;">println</span>(rangeOfThreeItems.firstValue)<span class="hljs-comment" style="box-sizing: border-box;">// 打印出来的结果: 0</span>rangeOfThreeItems.firstValue =<span class="hljs-number" style="box-sizing: border-box;"> 6</span><span class="hljs-comment" style="box-sizing: border-box;">// 现在的去见是 6, 7, 8</span><span class="hljs-built_in" style="box-sizing: border-box;">println</span>(rangeOfThreeItems.firstValue)<span class="hljs-comment" style="box-sizing: border-box;">// 打印出来的结果: 6</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li></ul>

这里要注意一下, 只有在定义var变量时才可以对结构体里面的变量进行修改, 如果是let的话, 就会报错, 比如:

<code class="hljs vhdl has-numbering" style="display: block; padding: 0px; background-color: transparent; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal;">rangeOfThreeItems.length = <span class="hljs-number" style="box-sizing: border-box;">3</span>// 报错: Connot assign <span class="hljs-keyword" style="box-sizing: border-box;">to</span> <span class="hljs-attribute" style="box-sizing: border-box;">'length</span>' <span class="hljs-keyword" style="box-sizing: border-box;">in</span> <span class="hljs-attribute" style="box-sizing: border-box;">'rangeOfThreeItems</span>'</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li></ul>

2.延迟存储属性

所谓的延迟存储属性是指当第一次被调用的时候才会计算其初始值的属性, 在属性声明前使用 lazy 来标示一个延迟存储属性, 比如:

<code class="hljs scala has-numbering" style="display: block; padding: 0px; background-color: transparent; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal;"><span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="box-sizing: border-box;">class</span> <span class="hljs-title" style="box-sizing: border-box;">DataImporter</span> {</span>    <span class="hljs-comment" style="box-sizing: border-box;">/*        DataImporter 是一个将外部文件中的数据导入的类。        这个类的初始化会消耗不少时间。    */</span>    <span class="hljs-keyword" style="box-sizing: border-box;">var</span> fileName = <span class="hljs-string" style="box-sizing: border-box;">"data.txt"</span><span class="hljs-comment" style="box-sizing: border-box;">// 这是提供数据导入功能</span>}<span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="box-sizing: border-box;">class</span> <span class="hljs-title" style="box-sizing: border-box;">DataManager</span> {</span>    <span class="hljs-keyword" style="box-sizing: border-box;">lazy</span> <span class="hljs-keyword" style="box-sizing: border-box;">var</span> importer = DataImporter()    <span class="hljs-keyword" style="box-sizing: border-box;">var</span> data = [String]()<span class="hljs-comment" style="box-sizing: border-box;">// 这是提供数据管理功能</span>}let manager = DataManager()manager.data.append(<span class="hljs-string" style="box-sizing: border-box;">"Some data"</span>)manager.data.append(<span class="hljs-string" style="box-sizing: border-box;">"Some more data"</span>)println(manager.importer.fileName)<span class="hljs-comment" style="box-sizing: border-box;">// 打印出来的结果: data.txt</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li></ul>

PS: 必须将延迟存储属性声明成变量(使用 var 关键字), 因为属性的值在实例构造完成之前可能无法得到, 而常量属性在构造过程完成之前必须要有初始值,因此无法声明成延迟属性.

解释一下这个例子, DataManager这个类里面有一个用来存储字符串数组的变量data, 而DataManager需要一个用来导入文件数据的类, 这个功能由DataImporter完成, 但在这里有一个问题, DataImporter这个类如果要初始化的话, 那么就会影响一定的性能, 因为它在初始化的时候还有可能要去打开文件, 并且还要读取到文件的内容, 所以在实例的时候, 没必去创建一个DataImporter, 而是在我们需要用到的时候才去创建, 而lazy就是为了这个理念而创建的关键字.

例子中就只有println的时候才会去用到DataImporter, 所以在println的时候才会被创建.


3.存储属性和实例变量

在Swift中的属性和在OC中的属性不太一样, 在OC中有两种方式在类实例存储值和引用, 对于属性来说, 也可以使用实例变量作为属性值的后端存储.

Swift 编程语言中把这些理论统一用属性来实现, Swift 中的属性没有对应的实例变量, 属性的后端存储也无法直接访问, 这就避免了不同场景下访问方式的困扰,同时也将属性的定 义简化成一个语句, 一个类型中属性的全部信息——包括命名、类型和内存管理特征—— 都在唯一一个地方(类型定义中)定义.


4.计算属性

除存储属性外, 类、结构体和枚举可以定义计算属性,计算属性不直接存储值, 而是提供一个 getter 来获取值, 一个可选的 setter 来间接设置其他属性或变量的值, 比如:

<code class="hljs cs has-numbering" style="display: block; padding: 0px; background-color: transparent; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal;"><span class="hljs-keyword" style="box-sizing: border-box;">struct</span> Point {    <span class="hljs-keyword" style="box-sizing: border-box;">var</span> x = <span class="hljs-number" style="box-sizing: border-box;">0.0</span>, y = <span class="hljs-number" style="box-sizing: border-box;">0.0</span>}<span class="hljs-keyword" style="box-sizing: border-box;">struct</span> Size {    <span class="hljs-keyword" style="box-sizing: border-box;">var</span> width = <span class="hljs-number" style="box-sizing: border-box;">0.0</span>, height = <span class="hljs-number" style="box-sizing: border-box;">0.0</span>}<span class="hljs-keyword" style="box-sizing: border-box;">struct</span> Rect {    <span class="hljs-keyword" style="box-sizing: border-box;">var</span> origin = Point()    <span class="hljs-keyword" style="box-sizing: border-box;">var</span> size = Size()    <span class="hljs-keyword" style="box-sizing: border-box;">var</span> center: Point {        <span class="hljs-keyword" style="box-sizing: border-box;">get</span> {            <span class="hljs-keyword" style="box-sizing: border-box;">let</span> centerX = origin.x + (size.width / <span class="hljs-number" style="box-sizing: border-box;">2</span>)            <span class="hljs-keyword" style="box-sizing: border-box;">let</span> centerY = origin.y + (size.height / <span class="hljs-number" style="box-sizing: border-box;">2</span>)            <span class="hljs-keyword" style="box-sizing: border-box;">return</span> Point(x: centerX, y: centerY)        }        <span class="hljs-keyword" style="box-sizing: border-box;">set</span>(newCenter) {            origin.x = newCenter.x - (size.width / <span class="hljs-number" style="box-sizing: border-box;">2</span>)            origin.y = newCenter.y - (size.height / <span class="hljs-number" style="box-sizing: border-box;">2</span>)        }    }}<span class="hljs-keyword" style="box-sizing: border-box;">var</span> square = Rect(origin: Point(x: <span class="hljs-number" style="box-sizing: border-box;">0.0</span>, y: <span class="hljs-number" style="box-sizing: border-box;">0.0</span>), size: Size(width: <span class="hljs-number" style="box-sizing: border-box;">10.0</span>, height: <span class="hljs-number" style="box-sizing: border-box;">10.0</span>))<span class="hljs-keyword" style="box-sizing: border-box;">let</span> initialSquareCenter = square.centersquare.center = Point(x: <span class="hljs-number" style="box-sizing: border-box;">15.0</span>, y: <span class="hljs-number" style="box-sizing: border-box;">15.0</span>)println(<span class="hljs-string" style="box-sizing: border-box;">"square.origin is now at (\(square.origin.x), \(square.origin.y))"</span>)<span class="hljs-comment" style="box-sizing: border-box;">// 打印出来的结果: square.origin is now at (10.0, 10.0)</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li></ul>

PS: 这个例子定义了三种不同的几何形状的结构体: 
Point 封装了一个(x, y)的坐标  
Size 封装了一个 width 和 height 
Rect 表示一个有原点和尺寸的矩形

Rect 也提供了一个名为 center 的计算属性。一个矩形的中心点可以从原点和尺寸来算出,所以不需要将它以显式声明的Point来保存。Rect的计算属性center提供了自定义的 getter 和 setter 来获取和设置矩形的中心点,就像它有一个存储属性一样。

例子中接下来创建了一个名为 square 的 Rect 实例,初始值原点是(0, 0),宽度高度都是 10。 如图所示蓝色正方形。

square 的 center 属性可以通过点运算符(square.center)来访问,这会调用 getter 来获 取属性的值。跟直接返回已经存在的值不同,getter 实际上通过计算然后返回一个新的Point 来表示 square 的中心点。如代码所示,它正确返回了中心点(5, 5)。

center 属性之后被设置了一个新的值(15, 15),表示向右上方移动正方形到如图所示橙色正 方形的位置。设置属性 center 的值会调用 setter 来修改属性 origin 的 x 和 y 的值,从而实 现移动正方形到新的位置。 
例子


5.便捷setter声明

如果计算属性的 setter 没有定义表示新值的参数名,则可以使用默认名称 newValue。下面是使用了便捷 setter 声明的 Rect 结构体代码, 比如:

<code class="hljs avrasm has-numbering" style="display: block; padding: 0px; background-color: transparent; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal;">struct AlternativeRect {    var origin = Point()    var size = Size()    var center: Point {        get {            let centerX = origin<span class="hljs-preprocessor" style="box-sizing: border-box;">.x</span> + (size<span class="hljs-preprocessor" style="box-sizing: border-box;">.width</span> / <span class="hljs-number" style="box-sizing: border-box;">2</span>)            let centerY = origin<span class="hljs-preprocessor" style="box-sizing: border-box;">.y</span> + (size<span class="hljs-preprocessor" style="box-sizing: border-box;">.height</span> / <span class="hljs-number" style="box-sizing: border-box;">2</span>)            return Point(<span class="hljs-built_in" style="box-sizing: border-box;">x</span>: centerX, <span class="hljs-built_in" style="box-sizing: border-box;">y</span>: centerY)        }        <span class="hljs-keyword" style="box-sizing: border-box;">set</span> {            origin<span class="hljs-preprocessor" style="box-sizing: border-box;">.x</span> = newValue<span class="hljs-preprocessor" style="box-sizing: border-box;">.x</span> - (size<span class="hljs-preprocessor" style="box-sizing: border-box;">.width</span> / <span class="hljs-number" style="box-sizing: border-box;">2</span>)            origin<span class="hljs-preprocessor" style="box-sizing: border-box;">.y</span> = newValue<span class="hljs-preprocessor" style="box-sizing: border-box;">.y</span> - (size<span class="hljs-preprocessor" style="box-sizing: border-box;">.height</span> / <span class="hljs-number" style="box-sizing: border-box;">2</span>)        }    }}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li></ul>

6.只读计算属性

所谓的只读计算属性其实就是getter属性, 只读计算属性总是返回一个值,可 以通过点运算符访问,但不能设置新的值, 只读计算属性的声明可以去掉 get 关键字和花括号, 比如:

<code class="hljs cs has-numbering" style="display: block; padding: 0px; background-color: transparent; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal;"><span class="hljs-keyword" style="box-sizing: border-box;">struct</span> Cuboid {    <span class="hljs-keyword" style="box-sizing: border-box;">var</span> width = <span class="hljs-number" style="box-sizing: border-box;">0.0</span>, height = <span class="hljs-number" style="box-sizing: border-box;">0.0</span>, depth = <span class="hljs-number" style="box-sizing: border-box;">0.0</span>    <span class="hljs-keyword" style="box-sizing: border-box;">var</span> volume: Double {    <span class="hljs-keyword" style="box-sizing: border-box;">return</span> width * height * depth}}<span class="hljs-keyword" style="box-sizing: border-box;">let</span> fourByFiveByTwo = Cuboid(width: <span class="hljs-number" style="box-sizing: border-box;">4.0</span>, height: <span class="hljs-number" style="box-sizing: border-box;">5.0</span>, depth: <span class="hljs-number" style="box-sizing: border-box;">2.0</span>)println(<span class="hljs-string" style="box-sizing: border-box;">"the volume of fourByFiveByTwo is \(fourByFiveByTwo.volume)"</span>)<span class="hljs-comment" style="box-sizing: border-box;">// 打印出来的结果: the volume of fourByFiveByTwo is 40.0</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li></ul>

PS: 必须使用 var 关键字定义计算属性, 包括只读计算属性, 因为他们的值不是固定的, let 关键字只用来声明常量属性,表示初始化后再也无法修改的值.


7.属性监视器

属性监视器监控和响应属性值的变化, 每次属性被设置值的时候都会调用属性监视器, 甚至新的值和现在的值相同的时候也不例外.

可以为除了延迟存储属性之外的其他存储属性添加属性监视器,也可以通过重载属性的方式 为继承的属性(包括存储属性和计算属性)添加属性监视器.

PS: 不需要为无法重载的计算属性添加属性监视器, 因为可以通过 setter 直接监控和响应值的变化.

属性监视器的添加有几种方式, 比如:

1.willSet 在设置新的值之前调用

2.didSet 在新的值被设置之后立即调用

3.willSet 监视器会将新的属性值作为固定参数传入,在 willSet 的实现代码中可以为这个参数指定一个名称,如果不指定则参数仍然可用,这时使用默认名称 newValue 表示。

PS: willSet 和 didSet 监视器在属性初始化过程中不会被调用,他们只会当属性的值在初始化之外的地方被设置时被调用.

让我们来看看例子吧:

<code class="hljs javascript has-numbering" style="display: block; padding: 0px; background-color: transparent; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal;"><span class="hljs-keyword" style="box-sizing: border-box;">class</span> StepCounter {    <span class="hljs-keyword" style="box-sizing: border-box;">var</span> totalSteps: Int = <span class="hljs-number" style="box-sizing: border-box;">0</span> {        willSet(newTotalSteps) {            println(<span class="hljs-string" style="box-sizing: border-box;">"About to set totalSteps to \(newTotalSteps)"</span>)        }        didSet {            <span class="hljs-keyword" style="box-sizing: border-box;">if</span> totalSteps > oldValue {                println(<span class="hljs-string" style="box-sizing: border-box;">"Added \(totalSteps - oldValue) steps"</span>)            }        }    }}<span class="hljs-keyword" style="box-sizing: border-box;">let</span> stepCounter = StepCounter()stepCounter.totalSteps = <span class="hljs-number" style="box-sizing: border-box;">200</span><span class="hljs-comment" style="box-sizing: border-box;">// 打印出来的结果: About to set totalSteps to 200</span><span class="hljs-comment" style="box-sizing: border-box;">// 打印出来的结果: Added 200 steps</span>stepCounter.totalSteps = <span class="hljs-number" style="box-sizing: border-box;">360</span><span class="hljs-comment" style="box-sizing: border-box;">// 打印出来的结果: About to set totalSteps to 200</span><span class="hljs-comment" style="box-sizing: border-box;">// 打印出来的结果: Added 160 steps</span>stepCounter.totalSteps = <span class="hljs-number" style="box-sizing: border-box;">896</span><span class="hljs-comment" style="box-sizing: border-box;">// 打印出来的结果: About to set totalSteps to 896</span><span class="hljs-comment" style="box-sizing: border-box;">// 打印出来的结果: Added 536 steps</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li></ul>

PS: 根据我们前面对两个监视器的解释, 我们可以很简单的去了解例子中的运行, 首先我们存入第一个数值200, 会打印一句提示, 说我们已经存储了一个值, 由于里面没有老值, 所以他在didSet里面的运算结果是200 - 0, 最后的结果是200, 第二个存入的数值是360, 系统也会提示我们说有一个新值存入了, 然后继续在didSet里面运算, 360 - 200, 所以得出来的结果是160, 最后一个也是如此, 这里就不解释了, 还有一个注意点就是如果在 didSet 监视器里为属性赋值, 这个值会替换监视器之前设置的值.



前面我们把一些非常常用的东西, 以及使用的细节也说了, 比如函数, 方法, 变量这些, 都是我们经常见到的, 现在让我们继续往下学习:


1.附属脚本

附属脚本可以定义在类(Class)、结构体(structure)和枚举(enumeration)这些目标中, 可以认为是访问对象, 集合或序列的快捷方式, 不需要再调用实例的特定的赋值和访问方法.

比如, 我们定义了一个数组Array, 那么我们就可以用someArray[Index]这样子来取数组的元素, 同样的, Dictionary也是如此, someDictionary[key], 这样子我们就可以取出相应的值或者元素.


2.附属脚本的语法

附属脚本允许你通过在实例后面的方括号中传入一个或者多个的索引值来对实例进行访问和赋值, 语法类似于实例方法和计算型属性的混合, 比如:

<code class="hljs cs has-numbering" style="display: block; padding: 0px; background-color: transparent; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal;">subscript(Index: Int) -> Int{    <span class="hljs-keyword" style="box-sizing: border-box;">get</span> {        <span class="hljs-comment" style="box-sizing: border-box;">// 返回与入参匹配的Int类型的值</span>    }    <span class="hljs-keyword" style="box-sizing: border-box;">set</span>(newValue) {        <span class="hljs-comment" style="box-sizing: border-box;">// 进行赋值运算</span>    }}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li></ul>

PS: subscript只能在某个类, 结构体和枚举里面声明, 否则的话编译器就会报错, 并且如果写了newValue, 那么newValue的类型必须和附属脚本定义的返回类型相同, 当然, 如果与计算属性相同的入参, 那就可以不用写了.

这个是个完整的例子

<code class="hljs coffeescript has-numbering" style="display: block; padding: 0px; background-color: transparent; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal;">struct TimesTable {    <span class="hljs-reserved" style="box-sizing: border-box;">let</span> <span class="hljs-attribute" style="box-sizing: border-box;">multiplier</span>: Int    subscript<span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-params" style="box-sizing: border-box;">(index: Int)</span> -></span> Int {        <span class="hljs-keyword" style="box-sizing: border-box;">return</span> multiplier * index    }}<span class="hljs-reserved" style="box-sizing: border-box;">let</span> threeTimesTable = TimesTable(<span class="hljs-attribute" style="box-sizing: border-box;">multiplier</span>: <span class="hljs-number" style="box-sizing: border-box;">3</span>)println(<span class="hljs-string" style="box-sizing: border-box;">"3的6倍是\(threeTimesTable[6])"</span>)<span class="hljs-regexp" style="box-sizing: border-box;">//</span> 打印出来的结果: <span class="hljs-number" style="box-sizing: border-box;">3</span>的<span class="hljs-number" style="box-sizing: border-box;">6</span>倍是<span class="hljs-number" style="box-sizing: border-box;">18</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li></ul>

3.附属脚本的用法

一般附属脚本是用来访问集合(collection),列表(list)或序列(sequence)中元素的快捷方式, 我们可以在自己特定的类或结构体中自由的实现附属脚本来提供合适的功能, 比如:

<code class="hljs go has-numbering" style="display: block; padding: 0px; background-color: transparent; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal;"><span class="hljs-keyword" style="box-sizing: border-box;">var</span> numberOfLegs = [<span class="hljs-string" style="box-sizing: border-box;">"spider"</span>:<span class="hljs-number" style="box-sizing: border-box;"> 8</span>, <span class="hljs-string" style="box-sizing: border-box;">"ant"</span>:<span class="hljs-number" style="box-sizing: border-box;"> 6</span>, <span class="hljs-string" style="box-sizing: border-box;">"cat"</span>:<span class="hljs-number" style="box-sizing: border-box;"> 4</span>]numberOfLegs[<span class="hljs-string" style="box-sizing: border-box;">"bird"</span>] =<span class="hljs-number" style="box-sizing: border-box;"> 2</span><span class="hljs-built_in" style="box-sizing: border-box;">println</span>(numberOfLegs)<span class="hljs-comment" style="box-sizing: border-box;">// 打印出来的结果: [ant: 6, bird: 2, cat: 4, spider: 8]</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li></ul>

PS: Swift 中字典的附属脚本实现中, 在get部分返回值是Int?, 上例中的numberOfLegs字典通过下边返回的是一个 Int?或者说“可选的 int”,不是每个字典的索引都能得到一个整型值, 对于没有设过值的索引的访问返回的结果就是 nil, 同样想要从字典实例中删除某个索引下的值也只需要给这个索引赋值为 nil 就可以了.


4.附属脚本选项

虽然说附属脚本是允许任意数量的入参索引, 并且每个入参类型也没有限制, 舒服脚本的返回值也可以是任何类型, 包括变量参数和可变参数, 唯一一个不允许的就是在In-Out参数或者给参数设置默认值的时候是不允许的.

一个类或结构体可以根据自身需要提供多个附属脚本实现,在定义附属脚本时通过入参个类 型进行区分,使用附属脚本时会自动匹配合适的附属脚本实现运行,这就是附属脚本的重载, 比如:

<code class="hljs coffeescript has-numbering" style="display: block; padding: 0px; background-color: transparent; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal;">struct Matrix {    <span class="hljs-reserved" style="box-sizing: border-box;">let</span> <span class="hljs-attribute" style="box-sizing: border-box;">rows</span>: Int, <span class="hljs-attribute" style="box-sizing: border-box;">columns</span>: Int    <span class="hljs-reserved" style="box-sizing: border-box;">var</span> <span class="hljs-attribute" style="box-sizing: border-box;">grid</span>: [Double]    init(<span class="hljs-attribute" style="box-sizing: border-box;">rows</span>: Int, <span class="hljs-attribute" style="box-sizing: border-box;">columns</span>: Int) {        self.rows = rows        self.columns = columns        grid = Array(<span class="hljs-attribute" style="box-sizing: border-box;">count</span>: rows * columns, <span class="hljs-attribute" style="box-sizing: border-box;">repeatedValue</span>: <span class="hljs-number" style="box-sizing: border-box;">0.0</span>)    }    func indexIsValidForRow<span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-params" style="box-sizing: border-box;">(row: Int, column: Int)</span> -></span> Bool{        <span class="hljs-keyword" style="box-sizing: border-box;">return</span> row >= <span class="hljs-number" style="box-sizing: border-box;">0</span> && row < rows && column >= <span class="hljs-number" style="box-sizing: border-box;">0</span> && column < columns    }    subscript<span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-params" style="box-sizing: border-box;">(row: Int, column: Int)</span> -></span> Double {        get {            assert(indexIsValidForRow(row, <span class="hljs-attribute" style="box-sizing: border-box;">column</span>: column), <span class="hljs-string" style="box-sizing: border-box;">"Index out of range"</span>)            <span class="hljs-keyword" style="box-sizing: border-box;">return</span> grid[(row * columns) + column]        }        set {            assert(indexIsValidForRow(row, <span class="hljs-attribute" style="box-sizing: border-box;">column</span>: column), <span class="hljs-string" style="box-sizing: border-box;">"Index out of range"</span>)        }    }}<span class="hljs-reserved" style="box-sizing: border-box;">var</span> matrix = Matrix(<span class="hljs-attribute" style="box-sizing: border-box;">rows</span>: <span class="hljs-number" style="box-sizing: border-box;">2</span>, <span class="hljs-attribute" style="box-sizing: border-box;">columns</span>: <span class="hljs-number" style="box-sizing: border-box;">2</span>)<span class="hljs-reserved" style="box-sizing: border-box;">let</span> someValue = matrix[<span class="hljs-number" style="box-sizing: border-box;">0</span>, <span class="hljs-number" style="box-sizing: border-box;">1</span>]println(someValue)<span class="hljs-regexp" style="box-sizing: border-box;">//</span> 打印出来的结果: <span class="hljs-number" style="box-sizing: border-box;">0.0</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li></ul>

PS: 由于我们在调用时, 所设置的条件都是2, 一旦我们超过了这个范围, 就不符合我们所定义的条件, 所以编译器会引起断言.








0 0
原创粉丝点击