update 02/04

This commit is contained in:
numbbbbb
2014-06-10 15:52:22 +08:00
parent 49c28ff603
commit b5bf26fee7
44 changed files with 1473 additions and 320 deletions

View File

@ -46,7 +46,7 @@
<div class="book" data-level="1.1" data-basepath=".." data-revision="1402377857835">
<div class="book" data-level="1.1" data-basepath=".." data-revision="1402386668059">
<div class="book-header">
<!-- Actions Left -->
<a href="#" class="btn pull-left toggle-summary" aria-label="Toggle summary"><i class="fa fa-align-justify"></i></a>
@ -587,7 +587,7 @@
<div class="page-inner">
<section class="normal" id="section-gitbook_4">
<section class="normal" id="section-gitbook_386">
<h1 id="-swift">关于 Swift</h1>
<p>Swift 是一种新的编程语言,用于编写 iOS 和 OS X 应用。Swift 结合了 C 和 Objective-C 的优点并且不受C的兼容性的限制。Swift 使用安全的编程模式并添加了很多新特性这将使编程更简单扩展性更强也更有趣。除此之外Swift 还支持人见人爱的 Cocoa 和 Cocoa Touch 框架。拥有了这些特性Swift将重新定义软件开发。</p>

View File

@ -46,7 +46,7 @@
<div class="book" data-level="1.2" data-basepath=".." data-revision="1402377857835">
<div class="book" data-level="1.2" data-basepath=".." data-revision="1402386668059">
<div class="book-header">
<!-- Actions Left -->
<a href="#" class="btn pull-left toggle-summary" aria-label="Toggle summary"><i class="fa fa-align-justify"></i></a>
@ -587,7 +587,7 @@
<div class="page-inner">
<section class="normal" id="section-gitbook_5">
<section class="normal" id="section-gitbook_387">
<h1 id="swift-">Swift 初见</h1>
<p>本页内容包括:</p>

View File

@ -46,7 +46,7 @@
<div class="book" data-level="1" data-basepath=".." data-revision="1402377857835">
<div class="book" data-level="1" data-basepath=".." data-revision="1402386668059">
<div class="book-header">
<!-- Actions Left -->
<a href="#" class="btn pull-left toggle-summary" aria-label="Toggle summary"><i class="fa fa-align-justify"></i></a>
@ -587,7 +587,7 @@
<div class="page-inner">
<section class="normal" id="section-gitbook_6">
<section class="normal" id="section-gitbook_388">
<h1 id="-swift">欢迎使用 Swift</h1>
<p>在本章中您将了解 Swift 的特性和开发历史,并对 Swift 有一个初步的了解。</p>

View File

@ -46,7 +46,7 @@
<div class="book" data-level="2.1" data-basepath=".." data-revision="1402377857835">
<div class="book" data-level="2.1" data-basepath=".." data-revision="1402386668059">
<div class="book-header">
<!-- Actions Left -->
<a href="#" class="btn pull-left toggle-summary" aria-label="Toggle summary"><i class="fa fa-align-justify"></i></a>
@ -587,7 +587,7 @@
<div class="page-inner">
<section class="normal" id="section-gitbook_8">
<section class="normal" id="section-gitbook_390">
<h1 id="-">基础部分</h1>
<p>Swift 是 iOS 和 OS X 应用开发的一门新语言。然而,如果你有 C 或者 Objective-C 开发经验的话,你会发现 Swift 的很多内容都是你熟悉的。</p>

View File

@ -46,7 +46,7 @@
<div class="book" data-level="2.2" data-basepath=".." data-revision="1402377857835">
<div class="book" data-level="2.2" data-basepath=".." data-revision="1402386668059">
<div class="book-header">
<!-- Actions Left -->
<a href="#" class="btn pull-left toggle-summary" aria-label="Toggle summary"><i class="fa fa-align-justify"></i></a>
@ -587,7 +587,7 @@
<div class="page-inner">
<section class="normal" id="section-gitbook_30">
<section class="normal" id="section-gitbook_417">
<h1 id="-">基础运算符</h1>
<p>运算符是检查, 改变, 合并值的特殊符号或短语. 例如, 加号 <code>+</code> 把计算两个数的和(如 <code>let i = 1 + 2</code>). 复杂些的运行算包括逻辑与<code>&amp;&amp;</code>(如 <code>if enteredDoorCode &amp;&amp; passedRetinaScan</code>), 还有自增运算符 <code>++i</code> 这样让自身加一的便捷运算.</p>

View File

@ -46,7 +46,7 @@
<div class="book" data-level="2.3" data-basepath=".." data-revision="1402377857835">
<div class="book" data-level="2.3" data-basepath=".." data-revision="1402386668059">
<div class="book-header">
<!-- Actions Left -->
<a href="#" class="btn pull-left toggle-summary" aria-label="Toggle summary"><i class="fa fa-align-justify"></i></a>
@ -587,9 +587,10 @@
<div class="page-inner">
<section class="normal" id="section-gitbook_9">
<section class="normal" id="section-gitbook_391">
<h1 id="-strings-and-characters-">字符串和字符 (Strings and Characters)</h1>
<hr>
<p>本页包含内容:</p>
<ul>
<li>字符串字面量</li>
@ -604,63 +605,65 @@
<li>字符串大小写</li>
<li>Unicode</li>
</ul>
<hr>
<p><strong>String</strong> 是例如 &quot;hello, world&quot;, &quot;海贼王&quot; 这样的有序的 <strong>Character</strong> (字符) 类型的值的集合,通过 <strong>String</strong> 类型来表示。</p>
<p>Swift 的 <strong>String</strong><strong>Character</strong> 类型提供了一个快速的,兼容 Unicode 的方式来处理代码中的文本信息。
创建和操作字符串的语法与 C 语言中字符串操作相似,轻量并且易读。
字符串连接操作只需要简单地通过 <code>+</code> 号将两个字符串相连即可。
字符串连接操作只需要简单地通过<code>+</code>号将两个字符串相连即可。
与 Swift 中其他值一样,能否更改字符串的值,取决于其被定义为常量还是变量。</p>
<p>尽管语法简易,但 <strong>String</strong> 类型是一种快速、现代化的字符串实现。
每一个字符串都是由独立编码的 Unicode 字符组成,并提供了以不同 Unicode 表示 (representations) 来访问这些字符的支持。</p>
<p>Swift可以在常量、变量、字面量和表达式中进行字符串插值操作可以轻松创建用于展示、存储和打印的自定义字符串。</p>
<blockquote>
<p>注意:</p>
<p>Swift 的 <strong>String</strong> 类型与 Foundation NSString 类进行了无缝桥接。
<p>注意:
Swift 的 <strong>String</strong> 类型与 Foundation NSString 类进行了无缝桥接。
如果您利用 Cocoa 或 Cocoa Touch 中的 Foundation 框架进行工作。
所有 <strong>NSString</strong> API 都可以调用您创建的任意 <strong>String</strong> 类型的值。
除此之外,还可以使用本章介绍的 <strong>String</strong> 特性。
您也可以在任意要求传入 <strong>NSString</strong> 实例作为参数的 API 中使用 <strong>String</strong> 类型的值作为替代。</p>
<p>更多关于在 Foundation 和 Cocoa 中使用 <strong>String</strong> 的信息请查看 <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/BuildingCocoaApps/index.html#//apple_ref/doc/uid/TP40014216" target="_blank">Using Swift with Cocoa and Objective-C</a></p>
<p>更多关于在 Foundation 和 Cocoa 中使用 <strong>String</strong> 的信息请查看 <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/BuildingCocoaApps/index.html#//apple_ref/doc/uid/TP40014216" target="_blank">Using Swift with Cocoa and Objective-C</a>(<strong>章节信息url需要替换</strong>)</p>
</blockquote>
<p><a name="string_literals"></a></p>
<h3 id="-string-literals-">字符串字面量 (String Literals)</h3>
<hr>
<h3 id="-">字符串字面量</h3>
<p>您可以在您的代码中包含一段预定义的字符串值作为字符串字面量。
字符串字面量是由双引号 (&quot;&quot;) 包裹着的具有固定顺序的文本字符集。</p>
<p>字符串字面量可以用于为常量和变量提供初始值。</p>
<pre><code>let someString = &quot;Some string literal value&quot;
</code></pre><blockquote>
<p>注意:</p>
<p><code>someString</code> 变量通过字符串字面量进行初始化Swift 因此推断该变量为 <strong>String</strong> 类型。</p>
<p>注意:
<code>someString</code>变量通过字符串字面量进行初始化Swift 因此推断该变量为 <strong>String</strong> 类型。</p>
</blockquote>
<p>字符串字面量可以包含以下特殊字符:</p>
<ul>
<li>转义字符 <code>\0</code> (空字符)、<code>\\</code>(反斜线)、<code>\t</code> (水平制表符)、<code>\n</code> (换行符)、<code>\r</code> (回车符)、<code>\&quot;</code> (双引号)、<code>\&#39;</code> (单引号)。</li>
<li>单字节 Unicode 标量,写成 <code>\xnn</code>,其中 <code>nn</code> 为两位十六进制数。</li>
<li>双字节 Unicode 标量,写成 <code>\unnnn</code>,其中 <code>nnnn</code> 为四位十六进制数。</li>
<li>四字节 Unicode 标量,写成 <code>\Unnnnnnnn</code>,其中 <code>nnnnnnnn</code> 为八位十六进制数。</li>
<li>转义字符<code>\0</code>(空字符)、<code>\\</code>(反斜线)、<code>\t</code>(水平制表符)、<code>\n</code>(换行符)、<code>\r</code>(回车符)、<code>\&quot;</code>(双引号)、<code>\&#39;</code>(单引号)。</li>
<li>单字节 Unicode 标量,写成<code>\xnn</code>,其中<code>nn</code>为两位十六进制数。</li>
<li>双字节 Unicode 标量,写成<code>\unnnn</code>,其中<code>nnnn</code>为四位十六进制数。</li>
<li>四字节 Unicode 标量,写成<code>\Unnnnnnnn</code>,其中<code>nnnnnnnn</code>为八位十六进制数。</li>
</ul>
<p>下面的代码为各种特殊字符的使用示例。
<code>wiseWords</code> 常量包含了两个转移特殊字符 (双括号)
<code>dollarSign</code><code>blackHeart</code><code>sparklingHeart</code> 常量演示了三种不同格式的 Unicode 标量:</p>
<code>wiseWords</code>常量包含了两个转移特殊字符 (双括号)
<code>dollarSign</code><code>blackHeart</code><code>sparklingHeart</code>常量演示了三种不同格式的 Unicode 标量:</p>
<pre><code>let wiseWords = &quot;\&quot;我是要成为海贼王的男人\&quot; - 路飞&quot;
// &quot;我是要成为海贼王的男人&quot; - 路飞
let dollarSign = &quot;\x24&quot; // $, Unicode 标量 U+0024
let blackHeart = &quot;\u2665&quot; // ♥, Unicode 标量 U+2665
let sparklingHeart = &quot;\U0001F496&quot; // 💖, Unicode 标量 U+1F496
</code></pre><hr>
<h3 id="-">初始化空字符串</h3>
</code></pre><p><a name="initializing_an_empty_string"></a></p>
<h3 id="-initializing-an-empty-string-">初始化空字符串 (Initializing an Empty String)</h3>
<hr>
<p>为了构造一个很长的字符串,可以创建一个空字符串作为初始值。
可以将空的字符串字面量赋值给变量,也可以初始化一个新的 <strong>String</strong> 实例:</p>
<pre><code>var emptyString = &quot;&quot; // 空字符串字面量
var anotherEmptyString = String() // 初始化 String 实例
// 两个字符串均为空并等价。
</code></pre><p>您可以通过检查其 <strong>Boolean</strong> 类型的 <code>isEmpty</code> 属性来判断该字符串是否为空:</p>
</code></pre><p>您可以通过检查其 <strong>Boolean</strong> 类型的<code>isEmpty</code>属性来判断该字符串是否为空:</p>
<pre><code>if emptyString.isEmpty {
println(&quot;什么都没有&quot;)
}
// 输出 &quot;什么都没有&quot;
</code></pre><hr>
<h3 id="-">字符串可变性</h3>
</code></pre><p><a name="string_mutability"></a></p>
<h3 id="-string-mutability-">字符串可变性 (String Mutability)</h3>
<hr>
<p>您可以通过将一个特定字符串分配给一个变量来对其进行修改,或者分配给一个常量来保证其不会被修改:</p>
<pre><code>var variableString = &quot;Horse&quot;
variableString += &quot; and carriage&quot;
@ -669,28 +672,30 @@ let constantString = &quot;Highlander&quot;
constantString += &quot; and another Highlander&quot;
// 这会报告一个编译错误 (compile-time error) - 常量不可以被修改。
</code></pre><blockquote>
<p>注意:</p>
<p>在 Objective-C 和 Cocoa 中,您通过选择两个不同的类( <code>NSString</code><code>NSMutableString</code> )来指定该字符串是否可以被修改Swift 中的字符串是否可以修改仅通过定义的是变量还是常量来决定,实现了多种类型可变性操作的统一。</p>
<p>注意:
在 Objective-C 和 Cocoa 中,您通过选择两个不同的类(<code>NSString</code><code>NSMutableString</code>)来指定该字符串是否可以被修改Swift 中的字符串是否可以修改仅通过定义的是变量还是常量来决定,实现了多种类型可变性操作的统一。</p>
</blockquote>
<p><a name="strings_are_value_types"></a></p>
<h3 id="-strings-are-value-types-">字符串是值类型 (Strings Are Value Types)</h3>
<hr>
<h3 id="-">字符串是值类型</h3>
<p>Swift 的 <strong>String</strong> 类型是值类型。
如果您创建了一个新的字符串,那么当其进行常量、变量赋值操作或在函数/方法中传递时,会进行值拷贝。
任何情况下,都会对已有字符串值创建新副本,并对该新副本进行传递或赋值操作。
值类型在 <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/ClassesAndStructures.html#//apple_ref/doc/uid/TP40014097-CH13-XID_104" target="_blank">Structures and Enumerations Are Value Types</a> 中进行了说明。</p>
值类型在 <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/ClassesAndStructures.html#//apple_ref/doc/uid/TP40014097-CH13-XID_104" target="_blank">Structures and Enumerations Are Value Types</a>(<strong>章节信息URL需要替换</strong>) 中进行了说明。</p>
<blockquote>
<p>注意:</p>
<p>与 Cocoa 中的 NSString 不同,当您在 Cocoa 中创建了一个 NSString 实例,并将其传递给一个函数/方法,或者赋值给一个变量,您传递或赋值的是该 NSString 实例的一个引用,除非您特别要求进行值拷贝,否则字符串不会生成新的副本来进行赋值操作。</p>
<p>注意:
与 Cocoa 中的<code>NSString</code>不同,当您在 Cocoa 中创建了一个<code>NSString</code>实例,并将其传递给一个函数/方法,或者赋值给一个变量,您传递或赋值的是该<code>NSString</code>实例的一个引用,除非您特别要求进行值拷贝,否则字符串不会生成新的副本来进行赋值操作。</p>
</blockquote>
<p>Swift 默认字符串拷贝的方式保证了在函数/方法中传递的是字符串的值。
很明显无论该值来自于哪里,都是您独自拥有的。
您可以放心您传递的字符串本身不会被更改。</p>
<p>在实际编译时Swift 编译器会优化字符串的使用,使实际的复制只发生在绝对必要的情况下,这意味着您将字符串作为值类型的同时可以获得极高的性能。</p>
<p><a name="working_with_characters"></a></p>
<h3 id="-working-with-characters-">使用字符 (Working with Characters)</h3>
<hr>
<h3 id="-characters-">使用字符(Characters)</h3>
<p>Swift 的 <strong>String</strong> 类型表示特定序列的 <strong>Character</strong> (字符) 类型值的集合。
每一个字符值代表一个 Unicode 字符。
您可利用 for-in 循环来遍历字符串中的每一个字符:</p>
您可利用<code>for-in</code>循环来遍历字符串中的每一个字符:</p>
<pre><code>for character in &quot;Dog!🐶&quot; {
println(character)
}
@ -699,27 +704,29 @@ constantString += &quot; and another Highlander&quot;
// g
// !
// 🐶
</code></pre><p>for-in 循环在<a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/ControlFlow.html#//apple_ref/doc/uid/TP40014097-CH9-XID_154" target="_blank">For Loops</a>中进行了详细描述。</p>
</code></pre><p>for-in 循环在<a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/ControlFlow.html#//apple_ref/doc/uid/TP40014097-CH9-XID_154" target="_blank">For Loops</a>(<strong>章节信息URL需要替换</strong>)中进行了详细描述。</p>
<p>另外,通过标明一个 <strong>Character</strong> 类型注解并通过字符字面量进行赋值,可以建立一个独立的字符常量或变量:</p>
<pre><code>let yenSign: Character = &quot;¥&quot;
</code></pre><hr>
<h3 id="-">计算字符数量</h3>
<p>通过调用全局 <code>countElements</code> 函数,并将字符串作为参数进行传递,可以获取该字符串的字符数量。</p>
</code></pre><p><a name="counting_characters"></a></p>
<h3 id="-counting-characters-">计算字符数量 (Counting Characters)</h3>
<hr>
<p>通过调用全局<code>countElements</code>函数,并将字符串作为参数进行传递,可以获取该字符串的字符数量。</p>
<pre><code>let unusualMenagerie = &quot;Koala 🐨, Snail 🐌, Penguin 🐧, Dromedary 🐪&quot;
println(&quot;unusualMenagerie has \(countElements(unusualMenagerie)) characters&quot;)
// prints &quot;unusualMenagerie has 40 characters&quot;
</code></pre><blockquote>
<p>注意:</p>
<p>不同的 Unicode 字符以及相同 Unicode 字符的不同表示方式可能需要不同数量的内存空间来存储。
所以Swift 中的字符在一个字符串中并不一定占用相同的内存空间。
<p>注意:
不同的 Unicode 字符以及相同 Unicode 字符的不同表示方式可能需要不同数量的内存空间来存储。
所以 Swift 中的字符在一个字符串中并不一定占用相同的内存空间。
因此字符串的长度不得不通过迭代字符串中每一个字符的长度来进行计算。
如果您正在处理一个长字符串,需要注意 <code>countElements</code> 函数必须遍历字符串中的字符以精准计算字符串的长度。</p>
<p>另外需要注意的是通过 <code>countElements</code> 返回的字符数量并不总是与包含相同字符的 NSString 的 <code>length</code> 属性相同。
NSString 的 <code>length</code> 属性是基于利用 UTF-16 表示的十六位代码单元数字,而不是基于 Unicode 字符。
为了解决这个问题,NSString 的 <code>length</code> 属性在被 Swift的 <strong>String</strong> 访问时会成为 <code>utf16count</code></p>
如果您正在处理一个长字符串,需要注意<code>countElements</code>函数必须遍历字符串中的字符以精准计算字符串的长度。</p>
<p>另外需要注意的是通过<code>countElements</code>返回的字符数量并不总是与包含相同字符的<code>NSString</code><code>length</code>属性相同。
<code>NSString</code><code>length</code>属性是基于利用 UTF-16 表示的十六位代码单元数字,而不是基于 Unicode 字符。
为了解决这个问题,<code>NSString</code><code>length</code>属性在被 Swift <strong>String</strong> 访问时会成为<code>utf16count</code></p>
</blockquote>
<p><a name="concatenating_strings_and_characters"></a></p>
<h3 id="-concatenating-strings-and-characters-">连接字符串和字符 (Concatenating Strings and Characters)</h3>
<hr>
<h3 id="-">连接字符串和字符</h3>
<p>字符串和字符的值可以通过加法运算符 (<code>+</code>) 相加在一起并创建一个新的字符串值:</p>
<pre><code>let string1 = &quot;hello&quot;
let string2 = &quot; there&quot;
@ -730,7 +737,7 @@ let stringPlusCharacter = string1 + character1 // 等于 &quot;hello!&quo
let stringPlusString = string1 + string2 // 等于 &quot;hello there&quot;
let characterPlusString = character1 + string1 // 等于 &quot;!hello&quot;
let characterPlusCharacter = character1 + character2 // 等于 &quot;!?&quot;
</code></pre><p>您也可以通过加法赋值运算符 (+=) 将一个字符串或者字符添加到一个已经存在字符串变量上:</p>
</code></pre><p>您也可以通过加法赋值运算符 (<code>+=</code>) 将一个字符串或者字符添加到一个已经存在字符串变量上:</p>
<pre><code>var instruction = &quot;look over&quot;
instruction += string2
// instruction 现在等于 &quot;look over there&quot;
@ -739,29 +746,32 @@ var welcome = &quot;good morning&quot;
welcome += character1
// welcome 现在等于 &quot;good morning!&quot;
</code></pre><blockquote>
<p>注意:</p>
<p>您不能将一个字符串或者字符添加到一个已经存在的字符变量上,因为字符变量只能包含一个字符。</p>
<p>注意:
您不能将一个字符串或者字符添加到一个已经存在的字符变量上,因为字符变量只能包含一个字符。</p>
</blockquote>
<p><a name="string_interpolation"></a></p>
<h3 id="-string-interpolation-">字符串插值 (String Interpolation)</h3>
<hr>
<h3 id="-">字符串插值</h3>
<p>字符串插值是一种构建新字符串的方式,可以在其中包含常量、变量、字面量和表达式。
您插入的字符串字面量的每一项都被包裹在以反斜线为前缀的圆括号中:</p>
<pre><code>let multiplier = 3
let message = &quot;\(multiplier) 乘以 2.5 是 \(Double(multiplier) * 2.5)&quot;
// message is &quot;3 乘以 2.5 是 7.5&quot;
</code></pre><p>在上面的例子中,<code>multiplier</code> 作为 <code>\(multiplier)</code> 被插入到一个字符串字面量中。
当创建字符串执行插值计算时此占位符会被替换为 <code>multiplier</code> 实际的值。</p>
<p><code>multiplier</code> 的值也作为字符串中后面表达式的一部分。
该表达式计算 <code>Double(multiplier) * 2.5</code> 的值并将结果 (7.5) 插入到字符串中。
在这个例子中,表达式写为 <code>\(Double(multiplier) * 2.5)</code> 并包含在字符串字面量中。</p>
</code></pre><p>在上面的例子中,<code>multiplier</code>作为<code>\(multiplier)</code>被插入到一个字符串字面量中。
当创建字符串执行插值计算时此占位符会被替换为<code>multiplier</code>实际的值。</p>
<p><code>multiplier</code>的值也作为字符串中后面表达式的一部分。
该表达式计算<code>Double(multiplier) * 2.5</code>的值并将结果 (7.5) 插入到字符串中。
在这个例子中,表达式写为<code>\(Double(multiplier) * 2.5)</code>并包含在字符串字面量中。</p>
<blockquote>
<p>注意:</p>
<p>您插值字符串中写在括号中的表达式不能包含非转义双引号 (<code>&quot;</code>) 和反斜杠 (<code>\</code>),并且不能包含回车或换行符。</p>
<p>注意:
您插值字符串中写在括号中的表达式不能包含非转义双引号 (<code>&quot;</code>) 和反斜杠 (<code>\</code>),并且不能包含回车或换行符。</p>
</blockquote>
<p><a name="comparing_strings"></a></p>
<h3 id="-comparing-strings-">比较字符串 (Comparing Strings)</h3>
<hr>
<h3 id="-">比较字符串</h3>
<p>Swift 提供了三种方式来比较字符串的值:字符串相等,前缀相等和后缀相等。</p>
<h5 id="-">字符串相等</h5>
<p>Swift 提供了三种方式来比较字符串的值:字符串相等、前缀相等和后缀相等。</p>
<p><a name="string_equality"></a></p>
<h5 id="-string-equality-">字符串相等 (String Equality)</h5>
<p>如果两个字符串以同一顺序包含完全相同的字符,则认为两者字符串相等:</p>
<pre><code>let quotation = &quot;我们是一样一样滴.&quot;
let sameQuotation = &quot;我们是一样一样滴.&quot;
@ -769,11 +779,12 @@ if quotation == sameQuotation {
println(&quot;这两个字符串被认为是相同的&quot;)
}
// prints &quot;这两个字符串被认为是相同的&quot;
</code></pre><h5 id="-">前缀/后缀相等</h5>
<p>通过调用字符串的 <code>hasPrefix</code>/<code>hasSuffix</code> 方法来检查字符串是否拥有特定前缀/后缀。
</code></pre><p><a name="prefix_and_suffix_equality"></a></p>
<h5 id="-prefix-and-suffix-equality-">前缀/后缀相等 (Prefix and Suffix Equality)</h5>
<p>通过调用字符串的<code>hasPrefix</code>/<code>hasSuffix</code>方法来检查字符串是否拥有特定前缀/后缀。
两个方法均需要以字符串作为参数传入并传出 <strong>Boolean</strong> 值。
两个方法均执行基本字符串和前缀/后缀字符串之间逐个字符的比较操作。</p>
<p>下面的例子以一个字符串数组表示莎士比亚话剧 <code>罗密欧与朱丽叶</code> 中前两场的场景位置:</p>
<p>下面的例子以一个字符串数组表示莎士比亚话剧《罗密欧与朱丽叶》中前两场的场景位置:</p>
<pre><code>let romeoAndJuliet = [
&quot;Act 1 Scene 1: Verona, A public place&quot;,
&quot;Act 1 Scene 2: Capulet&#39;s mansion&quot;,
@ -787,7 +798,7 @@ if quotation == sameQuotation {
&quot;Act 2 Scene 5: Capulet&#39;s mansion&quot;,
&quot;Act 2 Scene 6: Friar Lawrence&#39;s cell&quot;
]
</code></pre><p>您可以利用 <code>hasPrefix</code> 方法来计算话剧中第一幕的场景数:</p>
</code></pre><p>您可以利用<code>hasPrefix</code>方法来计算话剧中第一幕的场景数:</p>
<pre><code>var act1SceneCount = 0
for scene in romeoAndJuliet {
if scene.hasPrefix(&quot;Act 1 &quot;) {
@ -796,69 +807,76 @@ for scene in romeoAndJuliet {
}
println(&quot;There are \(act1SceneCount) scenes in Act 1&quot;)
// prints &quot;There are 5 scenes in Act 1&quot;
</code></pre><h5 id="-">大写和小写字符串</h5>
<p>您可以通过字符串的 <code>uppercaseString</code><code>lowercaseString</code> 属性来访问大写/小写版本的字符串。</p>
</code></pre><p><a name="uppercase_and_lowercase_strings"></a></p>
<h5 id="-uppercase-and-lowercase-strings-">大写小写字符串 (Uppercase and Lowercase Strings)</h5>
<p>您可以通过字符串的<code>uppercaseString</code><code>lowercaseString</code>属性来访问大写/小写版本的字符串。</p>
<pre><code>let normal = &quot;Could you help me, please?&quot;
let shouty = normal.uppercaseString
// shouty 值为 &quot;COULD YOU HELP ME, PLEASE?&quot;
let whispered = normal.lowercaseString
// whispered 值为 &quot;could you help me, please?&quot;
</code></pre><hr>
</code></pre><p><a name="unicode"></a></p>
<h3 id="unicode">Unicode</h3>
<hr>
<p>Unicode 是一个国际标准,用于文本的编码和表示。
它使您可以用标准格式表示来自任意语言几乎所有的字符,并能够对文本文件或网页这样的外部资源中的字符进行读写操作。</p>
<p>Swift 的字符串和字符类型是完全兼容 Unicode 标准的,它支持如下所述的一系列不同的 Unicode 编码。</p>
<h6 id="unicode-terminology-">Unicode 术语(Terminology)</h6>
<p><a name="unicode_terminology"></a></p>
<h6 id="unicode-unicode-terminology-">Unicode 术语 (Unicode Terminology)</h6>
<p>Unicode 中每一个字符都可以被解释为一个或多个 unicode 标量。
字符的 unicode 标量是一个唯一的21位数字(和名称),例如 <code>U+0061</code> 表示小写的拉丁字母A (&quot;a&quot;)<code>U+1F425</code> 表示小幺鸡表情 (&quot;🐥&quot;)</p>
<p>当 Unicode 字符串被写进文本文件或其他存储结构当中,这些 unicode 标量将会按照 Unicode 定义的集中格式之一进行编码。其包括 <code>UTF-8</code> (以8位代码单元进行编码) 和 <code>UTF-16</code> (以16位代码单元进行编码)。</p>
<h5 id="-unicode-">字符串的 Unicode 表示</h5>
字符的 unicode 标量是一个唯一的21位数字(和名称),例如<code>U+0061</code>表示小写的拉丁字母A (&quot;a&quot;)<code>U+1F425</code>表示小幺鸡表情 (&quot;🐥&quot;)</p>
<p>当 Unicode 字符串被写进文本文件或其他存储结构当中,这些 unicode 标量将会按照 Unicode 定义的集中格式之一进行编码。其包括<code>UTF-8</code>(以8位代码单元进行编码) 和<code>UTF-16</code>(以16位代码单元进行编码)。</p>
<p><a name="unicode_representations_of_strings"></a></p>
<h5 id="-unicode-unicode-representations-of-strings-">字符串的 Unicode 表示 (Unicode Representations of Strings)</h5>
<p>Swift 提供了几种不同的方式来访问字符串的 Unicode 表示。</p>
<p>您可以利用 <code>for-in</code> 来对字符串进行遍历,从而以 Unicode 字符的方式访问每一个字符值。
该过程在 <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/StringsAndCharacters.html#//apple_ref/doc/uid/TP40014097-CH7-XID_376" target="_blank">Working with Characters</a> 中进行了描述。</p>
<p>您可以利用<code>for-in</code>来对字符串进行遍历,从而以 Unicode 字符的方式访问每一个字符值。
该过程在 <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/StringsAndCharacters.html#//apple_ref/doc/uid/TP40014097-CH7-XID_376" target="_blank">Working with Characters</a>(<strong>章节信息URL需要替换</strong>) 中进行了描述。</p>
<p>另外,能够以其他三种 Unicode 兼容的方式访问字符串的值:</p>
<ul>
<li>UTF-8 代码单元集合 (利用字符串的 <code>utf8</code> 属性进行访问)</li>
<li>UTF-16 代码单元集合 (利用字符串的 <code>utf16</code> 属性进行访问)</li>
<li>21位的 Unicode 标量值集合 (利用字符串的 <code>unicodeScalars</code> 属性进行访问)</li>
<li>UTF-8 代码单元集合 (利用字符串的<code>utf8</code>属性进行访问)</li>
<li>UTF-16 代码单元集合 (利用字符串的<code>utf16</code>属性进行访问)</li>
<li>21位的 Unicode 标量值集合 (利用字符串的<code>unicodeScalars</code>属性进行访问)</li>
</ul>
<p>下面由 <code>D</code> <code>o</code> <code>g</code> <code>!</code><code>🐶</code> (<code>DOG FACE</code>Unicode 标量为 <code>U+1F436</code>)组成的字符串中的每一个字符代表着一种不同的表示:</p>
<p>下面由<code>D``o``g``!</code><code>🐶</code>(<code>DOG FACE</code>Unicode 标量为<code>U+1F436</code>)组成的字符串中的每一个字符代表着一种不同的表示:</p>
<pre><code>let dogString = &quot;Dog!🐶&quot;
</code></pre><h5 id="utf-8">UTF-8</h5>
<p>您可以通过遍历字符串的 <code>utf8</code> 属性来访问它的 <code>UTF-8</code> 表示。
其为 <strong>UTF8View</strong> 类型的属性,<strong>UTF8View</strong> 是无符号8位 (<code>UInt8</code>) 值的集合,每一个 <code>UInt8</code> 值都是一个字符的 UTF-8 表示:</p>
</code></pre><p><a name="UTF-8"></a></p>
<h5 id="utf-8">UTF-8</h5>
<p>您可以通过遍历字符串的<code>utf8</code>属性来访问它的<code>UTF-8</code>表示。
其为 <strong>UTF8View</strong> 类型的属性,<strong>UTF8View</strong> 是无符号8位 (<code>UInt8</code>) 值的集合,每一个<code>UInt8</code>值都是一个字符的 UTF-8 表示:</p>
<pre><code>for codeUnit in dogString.utf8 {
print(&quot;\(codeUnit) &quot;)
}
print(&quot;\n&quot;)
// 68 111 103 33 240 159 144 182
</code></pre><p>上面的例子中前四个10进制代码单元值 (68, 111, 103, 33) 代表了字符 <code>D</code> <code>o</code> <code>g</code><code>!</code> ,他们的 UTF-8 表示与 ASCII 表示相同。
后四个代码单元值 (240, 159, 144, 182) 是 <code>DOG FACE</code> 的4位 UTF-8 表示。</p>
</code></pre><p>上面的例子中前四个10进制代码单元值 (68, 111, 103, 33) 代表了字符<code>D</code> <code>o</code> <code>g</code><code>!</code>,他们的 UTF-8 表示与 ASCII 表示相同。
后四个代码单元值 (240, 159, 144, 182) 是<code>DOG FACE</code>的4位 UTF-8 表示。</p>
<p><a name="UTF-16"></a></p>
<h5 id="utf-16">UTF-16</h5>
<p>您可以通过遍历字符串的 <code>utf16</code> 属性来访问它的 <code>UTF-16</code> 表示。
其为 <strong>UTF16View</strong> 类型的属性,<strong>UTF16View</strong> 是无符号16位 (<code>UInt16</code>) 值的集合,每一个 <code>UInt16</code> 都是一个字符的 UTF-16 表示:</p>
<p>您可以通过遍历字符串的<code>utf16</code>属性来访问它的<code>UTF-16</code>表示。
其为 <strong>UTF16View</strong> 类型的属性,<strong>UTF16View</strong> 是无符号16位 (<code>UInt16</code>) 值的集合,每一个<code>UInt16</code>都是一个字符的 UTF-16 表示:</p>
<pre><code>for codeUnit in dogString.utf16 {
print(&quot;\(codeUnit) &quot;)
}
print(&quot;\n&quot;)
// 68 111 103 33 55357 56374
</code></pre><p>同样,前四个代码单元值 (68, 111, 103, 33) 代表了字符 <code>D</code> <code>o</code> <code>g</code><code>!</code> ,他们的 UTF-16 代码单元和 UTF-8 完全相同。</p>
<p>第五和第六个代码单元值 (55357 and 56374) 是 <code>DOG FACE</code> 字符的UTF-16 表示。
第一个值为 <code>U+D83D</code> (十进制值为 55357),第二个值为 <code>U+DC36</code> (十进制值为 56374)。</p>
<h5 id="unicode-scalars-">Unicode 标量 (Scalars)</h5>
<p>您可以通过遍历字符串的 <code>unicodeScalars</code> 属性来访问它的 Unicode 标量表示。
其为 <strong>UnicodeScalarView</strong> 类型的属性, <strong>UnicodeScalarView</strong><code>UnicodeScalar</code> 的集合
<code>UnicodeScalar</code> 是21位的 Unicode 代码点。</p>
<p>每一个 <code>UnicodeScalar</code> 拥有一个值属性可以返回对应的21位数值<code>UInt32</code> 来表示</p>
</code></pre><p>同样,前四个代码单元值 (68, 111, 103, 33) 代表了字符<code>D</code> <code>o</code> <code>g</code><code>!</code>,他们的 UTF-16 代码单元和 UTF-8 完全相同。</p>
<p>第五和第六个代码单元值 (55357 and 56374) 是<code>DOG FACE</code>字符的UTF-16 表示。
第一个值为<code>U+D83D</code>(十进制值为 55357),第二个值为<code>U+DC36</code>(十进制值为 56374)。</p>
<p><a name="unicode_scalars"></a></p>
<h5 id="unicode-unicode-scalars-">Unicode 标量 (Unicode Scalars)</h5>
<p>您可以通过遍历字符串的<code>unicodeScalars</code>属性来访问它的 Unicode 标量表示
其为 <strong>UnicodeScalarView</strong> 类型的属性, <strong>UnicodeScalarView</strong><code>UnicodeScalar</code>的集合。
<code>UnicodeScalar</code>是21位的 Unicode 代码点</p>
<p>每一个<code>UnicodeScalar</code>拥有一个值属性可以返回对应的21位数值<code>UInt32</code>来表示。</p>
<pre><code>for scalar in dogString.unicodeScalars {
print(&quot;\(scalar.value) &quot;)
}
print(&quot;\n&quot;)
// 68 111 103 33 128054
</code></pre><p>同样,前四个代码单元值 (68, 111, 103, 33) 代表了字符 <code>D</code> <code>o</code> <code>g</code><code>!</code>
</code></pre><p>同样,前四个代码单元值 (68, 111, 103, 33) 代表了字符<code>D</code> <code>o</code> <code>g</code><code>!</code>
第五位数值128054是一个十六进制1F436的十进制表示。
其等同于 <code>DOG FACE</code> 的Unicode 标量 U+1F436。</p>
<p>作为查询字符值属性的一种替代方法,每个 <code>UnicodeScalar</code> 值也可以用来构建一个新的字符串值,比如在字符串插值中使用:</p>
其等同于<code>DOG FACE</code>的Unicode 标量 U+1F436。</p>
<p>作为查询字符值属性的一种替代方法,每个<code>UnicodeScalar</code>值也可以用来构建一个新的字符串值,比如在字符串插值中使用:</p>
<pre><code>for scalar in dogString.unicodeScalars {
println(&quot;\(scalar) &quot;)
}
@ -867,8 +885,7 @@ print(&quot;\n&quot;)
// g
// !
// 🐶
</code></pre><p></p>
</code></pre>
</section>

View File

@ -46,7 +46,7 @@
<div class="book" data-level="2.4" data-basepath=".." data-revision="1402377857835">
<div class="book" data-level="2.4" data-basepath=".." data-revision="1402386668059">
<div class="book-header">
<!-- Actions Left -->
<a href="#" class="btn pull-left toggle-summary" aria-label="Toggle summary"><i class="fa fa-align-justify"></i></a>
@ -587,9 +587,237 @@
<div class="page-inner">
<section class="normal" id="section-gitbook_21">
<section class="normal" id="section-gitbook_403">
<h1 id="-collection-types-">集合类型 (Collection Types)</h1>
<p>Swift语言提供经典的数组和字典两种集合类型来存储集合数据。数组用来按顺序存储相同类型的数据。字典虽然无序存储相同类型数据值但是需要由独有的标识符引用和寻址就是键值对</p>
<p>Swift语言里的数组和字典中存储的数据值类型必须明确。 这意味着我们不能把不正确的数据类型插入其中。 同时这也说明我们完全可以对获取出的值类型非常自信。 Swift对显式类型集合的使用确保了我们的代码对工作所需要的类型非常清楚也让我们在开发中可以早早地找到任何的类型不匹配错误。</p>
<blockquote>
<p>注意:
Swift的数组结构在被声明成常量和变量或者被传入函数与方法中时会相对于其他类型展现出不同的特性。 获取更多信息请参见see Mutability of Collections and Assignment and Copy Behavior for Collection Types。集合的可变性与集合在赋值和复制中的行为章节</p>
</blockquote>
<h2 id="-">数组</h2>
<p>数组使用有序列表存储相同类型的多重数据。相同的值可以多次出现在一个数组的不同位置中。</p>
<p>Swift数组对存储数据有具体要求。 不同于 Objective-C的<code>NSArray</code><code>NSMutableArray</code>类,他们可以存储任何类型的实例而且不提供他们返回对象的任何本质信息。 在 Swift 中,数据值在被存储进入某个数组之前类型必须明确,方法是通过显式的类型标注或类型推断,而且不是必须是<code>class</code>类型。例如: 如果我们创建了一个<code>Int</code>值类型的数组,我们不能往其中插入任何不是<code>Int</code>类型的数据。 Swift 中的数组是类型安全的,并且它们中包含的类型必须明确。</p>
<h3 id="-">数组的简单语法</h3>
<p>写 Swift 数组应该遵循像<code>Array&lt;SomeType&gt;</code>这样的形式其中sometype是这个数组中唯一允许存在的数据类型。 我们也可以使用像<code>SomeType[]</code>这样的简单语法。 尽管两种形式在功能上是一样的, 但是我们推荐较短的那种,而且在本文中都会使用这种形式来使用数组。</p>
<h3 id="-">数组构造语句</h3>
<p>我们可以使用字面语句来进行数组构造,这是一种用一个或者多个数值构造数组的简单方法。字面语句是一系列由逗号分割并由方括号包含的数值。
<code>[value 1, value 2, value 3]</code></p>
<p>下面这个例子创建了一个叫做<code>shoppingList</code>并且存储字符串的数组:</p>
<pre><code>var shoppingList: String[] = [&quot;Eggs&quot;, &quot;Milk&quot;]
// shoppingList 已经被构造并且拥有两个初始项。
</code></pre><p><code>shoppingList</code>变量被声明为“字符串值类型的数组“,记作<code>String[]</code>。 因为这个数组被规定只有<code>String</code>一种数据结构,所以只有<code>String</code>类型可以在其中被存取。 在这里,<code>shoppinglist</code>数组由两个<code>String</code>值(<code>&quot;Eggs&quot;</code><code>&quot;Milk&quot;</code>)构造,并且由字面语句定义。</p>
<blockquote>
<p>注意:
<code>Shoppinglist</code>数组被声明为变量(<code>var</code>关键字创建)而不是常量(<code>let</code>创建)是因为以后可能会有更多的数据项被插入其中。</p>
</blockquote>
<p>在这个例子中,字面语句仅仅包含两个<code>String</code>值。匹配了该数组的变量声明(只能包含<code>String</code>的数组),所以这个字面语句的分配过程就是允许用两个初始项来构造<code>shoppinglist</code></p>
<p>由 于Swift 的类型推断机制,当我们用字面语句构造只拥有相同类型值数组的时候,我们不必把数组的类型定义清楚。 <code>shoppinglist</code>的构造也可以这样写:</p>
<pre><code>var shoppingList = [&quot;Eggs&quot;, &quot;Milk&quot;]
</code></pre><p>因为所有字面语句中的值都是相同的类型Swift 可以推断出<code>String[]</code><code>shoppinglist</code>中变量的正确类型。</p>
<h3 id="-">访问和修改数组</h3>
<p>我们可以通过数组的方法和属性来访问和修改数组,或者下标语法。
还可以使用数组的只读属性<code>count</code>来获取数组中的数据项数量。</p>
<pre><code>println(&quot;The shopping list contains \(shoppingList.count) items.&quot;)
// 打印出&quot;The shopping list contains 2 items.&quot;这个数组有2个项
</code></pre><p>使用布尔项<code>isEmpty</code>来作为检查<code>count</code>属性的值是否为0的捷径。</p>
<pre><code>if shoppingList.isEmpty {
println(&quot;The shopping list is empty.&quot;)
} else {
println(&quot;The shopping list is not empty.&quot;)
}
// 打印 &quot;The shopping list is not empty.&quot;shoppinglist不是空的
</code></pre><p>也可以使用<code>append</code>方法在数组后面添加新的数据项:</p>
<pre><code>shoppingList.append(&quot;Flour&quot;)
// shoppingList 现在有3个数据项有人在摊煎饼
</code></pre><p>除此之外,使用加法赋值运算符(<code>+=</code>)也可以直接在数组后面添加数据项:</p>
<pre><code>shoppingList += &quot;Baking Powder&quot;
// shoppingList 现在有四项了
</code></pre><p>我们也可以使用加法赋值运算符(<code>+=</code>)直接添加拥有相同类型数据的数组。</p>
<pre><code>shoppingList += [&quot;Chocolate Spread&quot;, &quot;Cheese&quot;, &quot;Butter&quot;]
// shoppingList 现在有7项了
</code></pre><p>可以直接使用下标语法来获取数组中的数据项,把我们需要的数据项的索引值放在直接放在数组名称的方括号中:</p>
<pre><code>var firstItem = shoppingList[0]
// 第一项是 &quot;Eggs&quot;
</code></pre><p>注意第一项在数组中的索引值是<code>0</code>而不是<code>1</code>。 Swift 中的数组索引总是从零开始。</p>
<p>我们也可以用下标来改变某个已有索引值对应的数据值:</p>
<pre><code>shoppingList[0] = &quot;Six eggs&quot;
// 其中的第一项现在是 &quot;Six eggs&quot; 而不是 &quot;Eggs&quot;
</code></pre><p>还可以利用下标来一次改变一系列数据值,即使新数据和原有数据的数量是不一样的。下面的例子把<code>&quot;Chocolate Spread&quot;</code><code>&quot;Cheese&quot;</code>,和<code>&quot;Butter&quot;</code>替换为<code>&quot;Bananas&quot;</code><code>&quot;Apples&quot;</code></p>
<pre><code>shoppingList[4...6] = [&quot;Bananas&quot;, &quot;Apples&quot;]
// shoppingList 现在有六项
</code></pre><blockquote>
<p>注意:
我们不能使用下标语法在数组尾部添加新项。如果我们试着用这种方法对索引越界的数据进行检索或者设置新值的操作,我们会引发一个运行期错误。我们可以使用索引值和数组的<code>count</code>属性进行比较来在使用某个索引之前先检验是否有效。除了当<code>count</code>等于0时说明这是个空数组最大索引值一直是<code>count - 1</code>,因为数组都是零起索引。</p>
</blockquote>
<p>调用数组的<code>insert(atIndex:)</code>方法来在某个具体索引值之前添加数据项:</p>
<pre><code>shoppingList.insert(&quot;Maple Syrup&quot;, atIndex: 0)
// shoppingList 现在有7项
// &quot;Maple Syrup&quot; 现在是这个列表中的第一项
</code></pre><p>这次<code>insert</code>函数调用把值为<code>&quot;Maple Syrup&quot;</code>的新数据项插入shopping列表的最开始位置并且使用<code>0</code>作为索引值。</p>
<p>类似的我们可以使用<code>removeAtIndex</code>方法来移除数组中的某一项。这个方法把数组在特定索引值中存储的数据项移除并且返回这个被移除的数据项(我们不需要的时候就可以无视它):</p>
<pre><code>let mapleSyrup = shoppingList.removeAtIndex(0)
//索引值为0的数据项被移除
// shoppingList 现在只有6项而且不包括Maple Syrup
// mapleSyrup常量的值等于被移除数据项的值 &quot;Maple Syrup&quot;
</code></pre><p>数据项被移除后数组中的空出项会被自动填补,所以现在索引值为<code>0</code>的数据项的值再次等于<code>&quot;Six eggs&quot;</code>:</p>
<pre><code>firstItem = shoppingList[0]
// firstItem 现在等于 &quot;Six eggs&quot;
</code></pre><p>如果我们只想把数组中的最后一项移除,可以使用<code>removeLast</code>方法而不是<code>removeAtIndex</code>方法来避免我们需要获取数组的<code>count</code>属性。就像后者一样,前者也会返回被移除的数据项:</p>
<pre><code>let apples = shoppingList.removeLast()
// 数组的最后一项被移除了
// shoppingList现在只有5项不包括cheese
// apples 常量的值现在等于&quot;Apples&quot; 字符串
</code></pre><h3 id="-">数组的遍历</h3>
<p>我们可以使用<code>for-in</code>循环来遍历所有数组中的数据项:</p>
<pre><code>for item in shoppingList {
println(item)
}
// Six eggs
// Milk
// Flour
// Baking Powder
// Bananas
</code></pre><p>如果我们同时需要每个数据项的值和索引值,可以使用全局<code>enumerate</code>函数来进行数组遍历。<code>enumerate</code>返回一个由每一个数据项索引值和数据值组成的键值对组。我们可以把这个键值对组分解成临时常量或者变量来进行遍历:</p>
<pre><code>for (index, value) in enumerate(shoppingList) {
println(&quot;Item \(index + 1): \(value)&quot;)
}
// Item 1: Six eggs
// Item 2: Milk
// Item 3: Flour
// Item 4: Baking Powder
// Item 5: Bananas
</code></pre><p>更多关于<code>for-in</code>循环的介绍请参见<a href="待添加链接">for循环</a></p>
<h3 id="-">创建并且构造一个数组</h3>
<p>我们可以使用构造语法来创建一个由特定数据类型构成的空数组:</p>
<pre><code>var someInts = Int[]()
println(&quot;someInts is of type Int[] with \(someInts。count) items。&quot;)
// 打印 &quot;someInts is of type Int[] with 0 items。&quot;someInts是0数据项的Int[]数组)
</code></pre><p>注意<code>someInts</code>被设置为一个<code>Int[]</code>构造函数的输出所以它的变量类型被定义为<code>Int[]</code></p>
<p>除此之外,如果代码上下文中提供了类型信息, 例如一个函数参数或者一个已经定义好类型的常量或者变量,我们可以使用空数组语句创建一个空数组,它的写法很简单:<code>[]</code>(一对空方括号):</p>
<pre><code>someInts.append(3)
// someInts 现在包含一个INT值
someInts = []
// someInts 现在是空数组但是仍然是Int[]类型的。
</code></pre><p>Swift 中的<code>Array</code>类型还提供一个可以创建特定大小并且所有数据都被默认的构造方法。我们可以把准备加入新数组的数据项数量(<code>count</code>)和适当类型的初始值(<code>repeatedValue</code>)传入数组构造函数:</p>
<pre><code>var threeDoubles = Double[](count: 3, repeatedValue:0.0)
// threeDoubles 是一种 Double[]数组, 等于 [0.0, 0.0, 0.0]
</code></pre><p>因为类型推断的存在,我们使用这种构造方法的时候不需要特别指定数组中存储的数据类型,因为类型可以从默认值推断出来:</p>
<pre><code>var anotherThreeDoubles = Array(count: 3, repeatedValue: 2.5)
// anotherThreeDoubles is inferred as Double[], and equals [2.5, 2.5, 2.5]
</code></pre><p>最后,我们可以使用加法操作符(<code>+</code>)来组合两种已存在的相同类型数组。新数组的数据类型会被从两个数组的数据类型中推断出来:</p>
<pre><code>var sixDoubles = threeDoubles + anotherThreeDoubles
// sixDoubles 被推断为 Double[], 等于 [0.0, 0.0, 0.0, 2.5, 2.5, 2.5]
</code></pre><h2 id="-">字典</h2>
<p>字典是一种存储相同类型多重数据的存储器。每个值value都关联独特的键key键作为字典中的这个值数据的标识符。和数组中的数据项不同字典中的数据项并没有具体顺序。我们在需要通过标识符访问数据的时候使用字典这种方法很大程度上和我们在现实世界中使用字典查字义的方法一样。</p>
<p>Swift 的字典使用时需要具体规定可以存储键和值类型。不同于 Objective-C 的<code>NSDictionary</code><code>NSMutableDictionary</code> 类可以使用任何类型的对象来作键和值并且不提供任何关于这些对象的本质信息。在 Swift 中,在某个特定字典中可以存储的键和值必须提前定义清楚,方法是通过显性类型标注或者类型推断。</p>
<p>Swift 的字典使用<code>Dictionary&lt;KeyType, ValueType&gt;</code>定义,其中<code>KeyType</code>是字典中键的数据类型,<code>ValueType</code>是字典中对应于这些键所存储值的数据类型。</p>
<p><code>KeyType</code>的唯一限制就是可哈希的,这样可以保证它是独一无二的,所有的 Swift 基本类型(例如<code>String</code><code>Int</code> <code>Double</code><code>Bool</code>)都是默认可哈希的,并且所有这些类型都可以在字典中当做键使用。未关联值的枚举成员(参见<a href="链接待添加">枚举</a>)也是默认可哈希的。</p>
<h2 id="-">字典字面语句</h2>
<p>我们可以使用字典字面语句来构造字典,他们和我们刚才介绍过的数组字面语句拥有相似语法。一个字典字面语句是一个定义拥有一个或者多个键值对的字典集合的简单语句。</p>
<p>一个键值对是一个<code>key</code>和一个<code>value</code>的结合体。在字典字面语句中,每一个键值对的键和值都由冒号分割。这些键值对构成一个列表,其中这些键值对由方括号包含并且由逗号分割:</p>
<pre><code>[key 1: value 1, key 2: value 2, key 3: value 3]
</code></pre><p>下面的例子创建了一个存储国际机场名称的字典。在这个字典中键是三个字母的国际航空运输相关代码,值是机场名称:</p>
<pre><code>var airports: Dictionary&lt;String, String&gt; = [&quot;TYO&quot;: &quot;Tokyo&quot;, &quot;DUB&quot;: &quot;Dublin&quot;]
</code></pre><p><code>airports</code>字典被定义为一种<code>Dictionary&lt;String, String&gt;</code>,它意味着这个字典的键和值都是<code>String</code>类型。</p>
<blockquote>
<p>注意:
<code>airports</code>字典被声明为变量(用<code>var</code>关键字)而不是常量(<code>let</code>关键字)因为后来更多的机场信息会被添加到这个示例字典中。</p>
</blockquote>
<p><code>airports</code>字典使用字典字面语句初始化,包含两个键值对。第一对的键是<code>TYO</code>,值是<code>Tokyo</code>。第二对的键是<code>DUB</code>,值是<code>Dublin</code></p>
<p>这个字典语句包含了两个<code>String: String</code>类型的键值对。他们对应<code>airports</code>变量声明的类型(一个只有<code>String</code>键和<code>String</code>值的字典)所以这个字典字面语句是构造两个初始数据项的<code>airport</code>字典。</p>
<p>和数组一样,如果我们使用字面语句构造字典就不用把类型定义清楚。<code>airports</code>的也可以用这种方法简短定义:</p>
<pre><code>var airports = [&quot;TYO&quot;: &quot;Tokyo&quot;, &quot;DUB&quot;: &quot;Dublin&quot;]
</code></pre><p>因为这个语句中所有的键和值都分别是相同的数据类型Swift 可以推断出<code>Dictionary&lt;String, String&gt;</code><code>airports</code>字典的正确类型。</p>
<h3 id="-">读取和修改字典</h3>
<p>我们可以通过字典的方法和属性来读取和修改字典,或者使用下标语法。和数组一样,我们可以通过字典的只读属性<code>count</code>来获取某个字典的数据项数量:</p>
<pre><code>println(&quot;The dictionary of airports contains \(airports.count) items.&quot;)
// 打印 &quot;The dictionary of airports contains 2 items.&quot;(这个字典有两个数据项)
</code></pre><p>我们也可以在字典中使用下标语法来添加新的数据项。可以使用一个合适类型的key作为下标索引并且分配新的合适类型的值</p>
<pre><code>airports[&quot;LHR&quot;] = &quot;London&quot;
// airports 字典现在有三个数据项
</code></pre><p>我们也可以使用下标语法来改变特定键对应的值:</p>
<pre><code>airports[&quot;LHR&quot;] = &quot;London Heathrow&quot;
// &quot;LHR&quot;对应的值 被改为 &quot;London Heathrow
</code></pre><p>作为另一种下标方法,字典的<code>updateValue(forKey:)</code>方法可以设置或者更新特定键对应的值。就像上面所示的示例,<code>updateValue(forKey:)</code>方法在这个键不存在对应值的时候设置值或者在存在时更新已存在的值。和上面的下标方法不一样,这个方法返回更新值之前的原值。这样方便我们检查更新是否成功。</p>
<p><code>updateValue(forKey:)</code>函数会返回包含一个字典值类型的可选值。举例来说:对于存储<code>String</code>值的字典,这个函数会返回一个<code>String?</code>或者“可选 <code>String</code>”类型的值。如果值存在,则这个可选值值等于被替换的值,否则将会是<code>nil</code></p>
<pre><code>if let oldValue = airports.updateValue(&quot;Dublin Internation&quot;, forKey: &quot;DUB&quot;) {
println(&quot;The old value for DUB was \(oldValue).&quot;)
}
// 打印出 &quot;The old value for DUB was Dublin.&quot;dub原值是dublin
</code></pre><p>我们也可以使用下标语法来在字典中检索特定键对应的值。由于使用一个没有值的键这种情况是有可能发生的,可选 类型返回这个键存在的相关值,否则就返回<code>nil</code></p>
<pre><code>if let airportName = airports[&quot;DUB&quot;] {
println(&quot;The name of the airport is \(airportName).&quot;)
} else {
println(&quot;That airport is not in the airports dictionary.&quot;)
}
// 打印 &quot;The name of the airport is Dublin INTernation.&quot;(机场的名字是都柏林国际)
</code></pre><p>我们还可以使用下标语法来通过给某个键的对应值赋值为<code>nil</code>来从字典里移除一个键值对:</p>
<pre><code>airports[&quot;APL&quot;] = &quot;Apple Internation&quot;
// &quot;Apple Internation&quot;不是真的 APL机场, 删除它
airports[&quot;APL&quot;] = nil
// APL现在被移除了
</code></pre><p>另外,<code>removeValueForKey</code>方法也可以用来在字典中移除键值对。这个方法在键值对存在的情况下会移除该键值对并且返回被移除的value或者在没有值的情况下返回<code>nil</code></p>
<pre><code>if let removedValue = airports.removeValueForKey(&quot;DUB&quot;) {
println(&quot;The removed airport&#39;s name is \(removedValue).&quot;)
} else {
println(&quot;The airports dictionary does not contain a value for DUB.&quot;)
}
// 打印 &quot;The removed airport&#39;s name is Dublin International.&quot;(被移除的机场名字是都柏林国际)
</code></pre><h3 id="-">字典遍历</h3>
<p>我们可以使用<code>for-in</code>循环来遍历某个字典中的键值对。每一个字典中的数据项都由<code>(key, value)</code>元组形式返回,并且我们可以使用暂时性常量或者变量来分解这些元组:</p>
<pre><code>for (airportCode, airportName) in airports {
prINTln(&quot;\(airportCode): \(airportName)&quot;)
}
// TYO: Tokyo
// LHR: London Heathrow
</code></pre><p><code>for-in</code>循环请参见<a href="链接待添加">For 循环</a></p>
<p>我们也可以通过访问他的<code>keys</code>或者<code>values</code>属性(都是可遍历集合)检索一个字典的键或者值:</p>
<pre><code>for airportCode in airports.keys {
prINTln(&quot;Airport code: \(airportCode)&quot;)
}
// Airport code: TYO
// Airport code: LHR
for airportName in airports。values {
prINTln(&quot;Airport name: \(airportName)&quot;)
}
// Airport name: Tokyo
// Airport name: London Heathrow
</code></pre><p>如果我们只是需要使用某个字典的键集合或者值集合来作为某个接受<code>Array</code>实例 API 的参数,可以直接使用<code>keys</code>或者<code>values</code>属性直接构造一个新数组:</p>
<pre><code>let airportCodes = Array(airports.keys)
// airportCodes is [&quot;TYO&quot;, &quot;LHR&quot;]
let airportNames = Array(airports.values)
// airportNames is [&quot;Tokyo&quot;, &quot;London Heathrow&quot;]
</code></pre><blockquote>
<p>注意:
Swift 的字典类型是无序集合类型。其中字典键,值,键值对在遍历的时候会重新排列,而且其中顺序是不固定的。</p>
</blockquote>
<h3 id="-">创建一个空字典</h3>
<p>我们可以像数组一样使用构造语法创建一个空字典:</p>
<pre><code>var namesOfIntegers = Dictionary&lt;Int, String&gt;()
// namesOfIntegers 是一个空的 Dictionary&lt;Int, String&gt;
</code></pre><p>这个例子创建了一个<code>Int, String</code>类型的空字典来储存英语对整数的命名。他的键是<code>Int</code>型,值是<code>String</code>型。</p>
<p>如果上下文已经提供了信息类型,我们可以使用空字典字面语句来创建一个空字典,记作<code>[:]</code>(中括号中放一个冒号):</p>
<pre><code>namesOfIntegers[16] = &quot;sixteen&quot;
// namesOfIntegers 现在包含一个键值对
namesOfIntegers = [:]
// namesOfIntegers 又成为了一个 Int, String类型的空字典
</code></pre><blockquote>
<p>注意:
在后台Swift 的数组和字典都是由泛型集合来实现的,想了解更多泛型和集合信息请参见<a href="链接待添加">泛型</a></p>
</blockquote>
<h2 id="-">集合的可变性</h2>
<p>数组和字典都是在单个集合中存储可变值。如果我们创建一个数组或者字典并且把它分配成一个变量,这个集合将会是可变的。这意味着我们可以在创建之后添加更多或移除已存在的数据项来改变这个集合的大小。与此相反,如果我们把数组或字典分配成常量,那么他就是不可变的,它的大小不能被改变。</p>
<p>对字典来说,不可变性也意味着我们不能替换其中任何现有键所对应的值。不可变字典的内容在被首次设定之后不能更改。
不可变行对数组来说有一点不同,当然我们不能试着改变任何不可变数组的大小,但是我们可以重新设定相对现存索引所对应的值。这使得 Swift 数组在大小被固定的时候依然可以做的很棒。</p>
<p>Swift 数组的可变性行为同时影响了数组实例如何被分配和修改,想获取更多信息,请参见<a href="待翻译,链接待添加,请查看对应章节的翻译">Assignment and Copy Behavior for Collection Types</a></p>
<blockquote>
<p>注意:
在我们不需要改变数组大小的时候创建不可变数组是很好的习惯。如此 Swift 编译器可以优化我们创建的集合。</p>
</blockquote>
</section>

View File

@ -46,7 +46,7 @@
<div class="book" data-level="2.5" data-basepath=".." data-revision="1402377857835">
<div class="book" data-level="2.5" data-basepath=".." data-revision="1402386668059">
<div class="book-header">
<!-- Actions Left -->
<a href="#" class="btn pull-left toggle-summary" aria-label="Toggle summary"><i class="fa fa-align-justify"></i></a>
@ -587,7 +587,7 @@
<div class="page-inner">
<section class="normal" id="section-gitbook_22">
<section class="normal" id="section-gitbook_404">
<h1 id="-">控制流</h1>
<p>Swift提供了类似C语言的流程控制结构包括可以多次执行任务的<code>for</code><code>while</code>循环,基于特定条件选择执行不同代码分支的<code>if</code><code>switch</code>语句,还有控制流程跳转到其他代码的<code>break</code><code>continue</code>语句。</p>

View File

@ -46,7 +46,7 @@
<div class="book" data-level="2.6" data-basepath=".." data-revision="1402377857835">
<div class="book" data-level="2.6" data-basepath=".." data-revision="1402386668059">
<div class="book-header">
<!-- Actions Left -->
<a href="#" class="btn pull-left toggle-summary" aria-label="Toggle summary"><i class="fa fa-align-justify"></i></a>
@ -587,7 +587,7 @@
<div class="page-inner">
<section class="normal" id="section-gitbook_23">
<section class="normal" id="section-gitbook_405">
<h1 id="-functions-">函数Functions</h1>
<p>本页包含内容:</p>

View File

@ -46,7 +46,7 @@
<div class="book" data-level="2.7" data-basepath=".." data-revision="1402377857835">
<div class="book" data-level="2.7" data-basepath=".." data-revision="1402386668059">
<div class="book-header">
<!-- Actions Left -->
<a href="#" class="btn pull-left toggle-summary" aria-label="Toggle summary"><i class="fa fa-align-justify"></i></a>
@ -587,136 +587,153 @@
<div class="page-inner">
<section class="normal" id="section-gitbook_24">
<section class="normal" id="section-gitbook_406">
<h1 id="-">闭包</h1>
<hr>
<p>本页内容包含:</p>
<ul>
<li>闭包表达式</li>
<li>Trailing闭包</li>
<li>尾随闭包</li>
<li>值捕获</li>
<li>闭包是引用类型</li>
</ul>
<p>闭包是功能性自包含模块,可以在代码中被传递和使用。
Swift 中的闭包与 C 和 Objective-C 中的 <code>blocks</code> 以及其他一些编程语言中的 <code>lambdas</code> 比较相似。</p>
<p>闭包可以 <strong>捕获</strong> 和存储其所在上下文中任意常量和变量的引用。
这就是所谓的闭合并包裹着这些常量和变量俗称闭包。Swift 会为您管理在 <strong>捕获</strong> 过程中涉及到的内存操作。</p>
<p>闭包是自包含的函数代码块,可以在代码中被传递和使用。
Swift 中的闭包与 C 和 Objective-C 中的<code>blocks</code> (代码块) 以及其他一些编程语言中的<code>lambdas</code> (匿名函数) 比较相似。</p>
<p>闭包可以<strong>捕获</strong>和存储其所在上下文中任意常量和变量的引用。
这就是所谓的闭合并包裹着这些常量和变量俗称闭包。Swift 会为您管理在<strong>捕获</strong>过程中涉及到的所有内存操作。</p>
<blockquote>
<p>注意:</p>
<p>如果您不熟悉 <strong>捕获</strong> (capturing) 这个概念也不用担心,后面会详细对其进行介绍</p>
<p>注意:
如果您不熟悉<strong>捕获</strong> (capturing) 这个概念也不用担心,您可以在 <a href="#capturing_values">捕获值</a> 章节对其进行详细了解</p>
</blockquote>
<p> <code>函数</code> 章节中介绍的全局和嵌套函数实际上也是特殊的闭包,闭包采取如下三种形式之一:</p>
<p><code>函数</code> (<strong>这里需要函数章节提供相应链接进行配合</strong>) 章节中介绍的全局和嵌套函数实际上也是特殊的闭包,闭包采取如下三种形式之一:</p>
<ul>
<li>全局函数是一个有名字但不会捕获任何值的闭包</li>
<li>嵌套函数是一个有名字并可以捕获其封闭函数域内值的闭包</li>
<li>闭包表达式是一个利用轻量级语法所写的可以捕获其上下文中变量或常量值的没有名字的闭包</li>
<li>闭包表达式是一个利用轻量级语法所写的可以捕获其上下文中变量或常量值的匿名闭包</li>
</ul>
<p>Swift 的闭包表达式拥有简洁的风格,并鼓励在常见场景中进行语法优化,主要优化如下:</p>
<ul>
<li>利用上下文推断参数和返回值类型</li>
<li>单表达式闭包可以省略 <code>return</code> 关键字</li>
<li>隐式返回单表达式闭包,即单表达式闭包可以省略<code>return</code>关键字</li>
<li>参数名称缩写</li>
<li>Trailing 闭包语法</li>
<li>尾随 (Trailing) 闭包语法</li>
</ul>
<h3 id="-">闭包表达式</h3>
<p>嵌套函数是一个在较复杂函数中方便进行命名和定义自包含代码模块的方式。
<p><a name="closure_expressions"></a></p>
<h3 id="-closure-expressions-">闭包表达式 (Closure Expressions)</h3>
<hr>
<p>嵌套函数 (<strong>这里需要函数章节提供相应链接及锚点进行配合</strong>) 是一个在较复杂函数中方便进行命名和定义自包含代码模块的方式。
当然,有时候撰写小巧的没有完整定义和命名的类函数结构也是很有用处的,尤其是在您处理一些函数并需要将另外一些函数作为该函数的参数时。</p>
<p>闭包表达式是一种利用简洁语法构建内联闭包的方式。
闭包表达式提供了一些语法优化,使得撰写闭包变得简单明了。
下面闭包表达式的例子通过使用几次迭代展示了 <code>sort</code> 函数定义和语法优化的方式。
下面闭包表达式的例子通过使用几次迭代展示了<code>sort</code>函数定义和语法优化的方式。
每一次迭代都用更简洁的方式描述了相同的功能。</p>
<h5 id="-sort-"><code>sort</code> 函数</h5>
<p>Swift 标准库提供了 <code>sort</code> 函数,会根据您提供的排序闭包将已知类型数组中的值进行排序。
<p><a name="the_sort_function"></a></p>
<h5 id="sort-the-sort-function-">sort 函数 (The Sort Function)</h5>
<p>Swift 标准库提供了<code>sort</code>函数,会根据您提供的基于输出类型排序的闭包函数将已知类型数组中的值进行排序。
一旦排序完成,函数会返回一个与原数组大小相同的新数组,该数组中包含已经正确排序的同类型元素。</p>
<p>下面的闭包表达式示例使用 <code>sort</code> 函数对一个 <strong>String</strong> 类型的数组进行字母逆序排序,以下是初始数组值:</p>
<p>下面的闭包表达式示例使用<code>sort</code>函数对一个 <strong>String</strong> 类型的数组进行字母逆序排序,以下是初始数组值:</p>
<pre><code>let names = [&quot;Chris&quot;, &quot;Alex&quot;, &quot;Ewa&quot;, &quot;Barry&quot;, &quot;Daniella&quot;]
</code></pre><p>该例子对一个 <strong>String</strong> 类型的数组进行排序,因此排序闭包需为 <code>(String, String) -&gt; Bool</code> 类型的函数。</p>
<p>提供排序闭包的一种方式是撰写一个符合其类型要求的普通函数,并将其作为 <code>sort</code> 函数的第二个参数传入:</p>
</code></pre><p><code>sort</code>函数需要传入两个参数:</p>
<ul>
<li>已知类型的数组</li>
<li>闭包函数,该闭包函数需要传入与数组类型相同的两个值,并返回一个布尔类型值来告诉<code>sort</code>函数当排序结束后传入的第一个参数排在第二个参数前面还是后面。如果第一个参数值出现在第二个参数值前面,排序闭包函数需要返回<code>true</code>,反之返回<code>false</code></li>
</ul>
<p>该例子对一个 <strong>String</strong> 类型的数组进行排序,因此排序闭包函数类型需为<code>(String, String) -&gt; Bool</code></p>
<p>提供排序闭包函数的一种方式是撰写一个符合其类型要求的普通函数,并将其作为<code>sort</code>函数的第二个参数传入:</p>
<pre><code>func backwards(s1: String, s2: String) -&gt; Bool {
return s1 &gt; s2
}
var reversed = sort(names, backwards)
// reversed is equal to [&quot;Ewa&quot;, &quot;Daniella&quot;, &quot;Chris&quot;, &quot;Barry&quot;, &quot;Alex&quot;]
</code></pre><p>如果第一个字符串 (s1) 大于第二个字符串 (s2)<code>backwards</code> 函数返回 <code>true</code>,表示在新的数组中 s1 应该出现在 s2 前。
字符中的 &quot;大于&quot; 表示 &quot;按照字母顺序出现&quot;
这意味着字母 &quot;B&quot; 大于字母 &quot;A&quot;, 字符串 &quot;Tom&quot; 大于字符串 &quot;Tim&quot;
其将进行字母逆序排序,&quot;Barry&quot; 将会排在 &quot;Alex&quot; 之后。</p>
// reversed [&quot;Ewa&quot;, &quot;Daniella&quot;, &quot;Chris&quot;, &quot;Barry&quot;, &quot;Alex&quot;]
</code></pre><p>如果第一个字符串 (<code>s1</code>) 大于第二个字符串 (<code>s2</code>)<code>backwards</code>函数返回<code>true</code>,表示在新的数组中<code>s1</code>应该出现在<code>s2</code>前。
对于字符中的字符来说,&quot;大于&quot; 表示 &quot;按照字母顺序较晚出现&quot;
这意味着字母<code>&quot;B&quot;</code>大于字母<code>&quot;A&quot;</code>,字符串<code>&quot;Tom&quot;</code>大于字符串<code>&quot;Tim&quot;</code>
其将进行字母逆序排序,<code>&quot;Barry&quot;</code>将会排在<code>&quot;Alex&quot;</code>之后。</p>
<p>然而,这是一个相当冗长的方式,本质上只是写了一个单表达式函数 (a &gt; b)。
在下面的例子中,利用闭合表达式语法可以更好的构造一个内联排序闭包。</p>
<h5 id="-">闭包表达式语法</h5>
<p><a name="closure_expression_syntax"></a></p>
<h5 id="-closure-expression-syntax-">闭包表达式语法 (Closure Expression Syntax)</h5>
<p>闭包表达式语法有如下一般形式:</p>
<pre><code>{ (parameters) -&gt; returnType in
statements
}
</code></pre><p>闭包表达式语法可以使用常量、变量和 <code>inout</code> 类型作为参数,不提供默认值。
也可以在参数列表的最后使用可变参数。元组也可以作为参数和返回值。</p>
<p>下面的例子展示了之前 <code>backwards</code> 函数对应的闭包表达式版本的代码:</p>
</code></pre><p>闭包表达式语法可以使用常量、变量和<code>inout</code> (<strong>这里也需要函数章节提供相应链接和锚点进行配合</strong>) 类型作为参数,不提供默认值。
也可以在参数列表的最后使用可变参数。
元组也可以作为参数和返回值。</p>
<p>下面的例子展示了之前<code>backwards</code>函数对应的闭包表达式版本的代码:</p>
<pre><code>reversed = sort(names, { (s1: String, s2: String) -&gt; Bool in
return s1 &gt; s2
})
</code></pre><p>需要注意的是内联闭包参数和返回值类型声明与 <code>backwards</code> 函数类型声明相同。
在这两种方式中,都写成了 (s1: String, s2: String) -&gt; Bool。
</code></pre><p>需要注意的是内联闭包参数和返回值类型声明与<code>backwards</code>函数类型声明相同。
在这两种方式中,都写成了<code>(s1: String, s2: String) -&gt; Bool</code>
然而在内联闭包表达式中,函数和返回值类型都写在大括号内,而不是大括号外。</p>
<p>闭包的函数体部分由关键字 <code>in</code> 引入。
<p>闭包的函数体部分由关键字<code>in</code>引入。
该关键字表示闭包的参数和返回值类型定义已经完成,闭包函数体即将开始。</p>
<p>因为这个闭包的函数体部分如此短以至于可以将其改写成一行代码:</p>
<pre><code>reversed = sort(names, { (s1: String, s2: String) -&gt; Bool in return s1 &gt; s2 } )
</code></pre><p>这说明 <code>sort</code> 函数的整体调用保持不变,一对圆括号仍然包裹住了函数中整个参数集合。而其中一个参数现在变成了内联闭包 (相比于 <code>backwards</code> 版本的代码)。</p>
<h5 id="-">根据上下文推断类型</h5>
<p>因为排序闭包是作为函数的参数进行传入的Swift可以推断其参数和返回值的类型。
<code>sort</code> 期望第二个参数是类型为 <code>(String, String) -&gt; Bool</code> 的函数,因此实际上 <code>String</code>, <code>String</code><code>Bool</code> 类型并不需要作为闭包表达式定义中的一部分
因为所有的类型都可以被正确推断,返回箭头 (-&gt;) 和 围绕在参数周围的括号也可以被省略:</p>
</code></pre><p>这说明<code>sort</code>函数的整体调用保持不变,一对圆括号仍然包裹住了函数中整个参数集合。而其中一个参数现在变成了内联闭包 (相比于<code>backwards</code>版本的代码)。</p>
<p><a name="inferring_type_from_context"></a></p>
<h5 id="-inferring-type-from-context-">根据上下文推断类型 (Inferring Type From Context)</h5>
<p>因为排序闭包函数是作为<code>sort</code>函数的参数进行传入的Swift可以推断其参数和返回值的类型
<code>sort</code>期望第二个参数是类型为<code>(String, String) -&gt; Bool</code>的函数,因此实际上<code>String</code>,<code>String</code><code>Bool</code>类型并不需要作为闭包表达式定义中的一部分。
因为所有的类型都可以被正确推断,返回箭头 (<code>-&gt;</code>) 和围绕在参数周围的括号也可以被省略:</p>
<pre><code>reversed = sort(names, { s1, s2 in return s1 &gt; s2 } )
</code></pre><p>实际上任何情况下,通过内联闭包表达式构造的闭包作为参数传递给函数时,都可以推断出闭包的参数和返回值类型,这意味着您几乎不需要利用完整格式构造任何内联闭包。</p>
<h5 id="-return-">单行表达式闭包可以省略 <code>return</code></h5>
<p>表达式闭包可以通过隐藏 <code>return</code> 关键字来隐式返回单行表达式的结果,如上版本的例子可以改写为:</p>
<p><a name="implicit_returns_from_single_expression_closures"></a></p>
<h5 id="-implicit-return-from-single-expression-clossures-">单表达式闭包隐式返回 (Implicit Return From Single-Expression Clossures)</h5>
<p>单行表达式闭包可以通过隐藏<code>return</code>关键字来隐式返回单行表达式的结果,如上版本的例子可以改写为:</p>
<pre><code>reversed = sort(names, { s1, s2 in s1 &gt; s2 } )
</code></pre><p>在这个例子中,<code>sort</code> 函数的第二个参数函数类型明确了闭包必须返回一个 <strong>Bool</strong> 类型值。
因为闭包函数体只包含了一个单一表达式 (s1 &gt; s2),该表达式返回 <strong>Bool</strong> 类型值,因此这里没有歧义,<code>return</code>关键字可以省略。</p>
<h5 id="-">参数名称缩写</h5>
<p>Swift 自动为内联函数提供了参数名称缩写功能,您可以直接通过 <code>$0</code>,<code>$1</code>,<code>$2</code> 来顺序调用闭包的参数。</p>
</code></pre><p>在这个例子中,<code>sort</code>函数的第二个参数函数类型明确了闭包必须返回一个 <strong>Bool</strong> 类型值。
因为闭包函数体只包含了一个单一表达式 (<code>s1 &gt; s2</code>),该表达式返回 <strong>Bool</strong> 类型值,因此这里没有歧义,<code>return</code>关键字可以省略。</p>
<p><a name="shorthand_argument_names"></a></p>
<h5 id="-shorthand-argument-names-">参数名称缩写 (Shorthand Argument Names)</h5>
<p>Swift 自动为内联函数提供了参数名称缩写功能,您可以直接通过<code>$0</code>,<code>$1</code>,<code>$2</code>来顺序调用闭包的参数。</p>
<p>如果您在闭包表达式中使用参数名称缩写,您可以在闭包参数列表中省略对其的定义,并且对应参数名称缩写的类型会通过函数类型进行推断。
<code>in</code> 关键字也同样可以被省略,因为此时闭包表达式完全由闭包函数体构成:</p>
<code>in</code>关键字也同样可以被省略,因为此时闭包表达式完全由闭包函数体构成:</p>
<pre><code>reversed = sort(names, { $0 &gt; $1 } )
</code></pre><p>在这个例子中,<code>$0</code><code>$1</code> 表示闭包中第一个和第二个 <strong>String</strong> 类型的参数。</p>
<h5 id="-">运算符函数</h5>
</code></pre><p>在这个例子中,<code>$0</code><code>$1</code>表示闭包中第一个和第二个 <strong>String</strong> 类型的参数。</p>
<p><a name="operator_functions"></a></p>
<h5 id="-operator-functions-">运算符函数 (Operator Functions)</h5>
<p>实际上还有一种更简短的方式来撰写上面例子中的闭包表达式。
Swift 的 <strong>String</strong> 类型定义了关于大于号 (&gt;) 的字符串实现,其作为一个函数接受两个 <strong>String</strong> 类型的参数并返回 <strong>Bool</strong> 类型的值。
而这正好与 <code>sort</code> 函数的第二个参数需要的函数类型相符合。
Swift 的 <strong>String</strong> 类型定义了关于大于号 (<code>&gt;</code>) 的字符串实现,其作为一个函数接受两个 <strong>String</strong> 类型的参数并返回 <strong>Bool</strong> 类型的值。
而这正好与<code>sort</code>函数的第二个参数需要的函数类型相符合。
因此您可以简单地传递一个大于号Swift可以自动推断出您想使用大于号的字符串函数实现</p>
<pre><code>reversed = sort(names, &gt;)
</code></pre><p>更多关于运算符表达式的内容请查看 <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/AdvancedOperators.html#//apple_ref/doc/uid/TP40014097-CH27-XID_43" target="_blank">Operator Functions</a></p>
<h3 id="trailing-">Trailing 闭包</h3>
<p>如果您需要将一个很长的闭包表达式作为最后一个参数传递给函数,可以使用 trailing 闭包来增强函数的可读性。
Trailing 闭包是一个书写在函数括号之外(之后)的闭包表达式,函数支持将其作为最后一个参数调用。</p>
</code></pre><p>更多关于运算符表达式的内容请查看 <a href="">Operator Functions</a> (<strong>这里需要 Operator Functions 进行配合</strong>)</p>
<p><a name="trailing_closures"></a></p>
<h3 id="-trailing-closures-">尾随闭包 (Trailing Closures)</h3>
<hr>
<p>如果您需要将一个很长的闭包表达式作为最后一个参数传递给函数,可以使用尾随闭包来增强函数的可读性。
尾随闭包是一个书写在函数括号之外(之后)的闭包表达式,函数支持将其作为最后一个参数调用。</p>
<pre><code>func someFunctionThatTakesAClosure(closure: () -&gt; ()) {
// 函数体部分
}
// 以下是不使用 trailing 闭包进行函数调用
// 以下是不使用尾随闭包进行函数调用
someFunctionThatTakesAClosure({
// 闭包主体部分
})
// 以下是使用 trailing 闭包进行函数调用
// 以下是使用尾随闭包进行函数调用
someFunctionThatTakesAClosure() {
// 闭包主体部分
}
</code></pre><blockquote>
<p>注意:</p>
<p>如果函数只需要闭包表达式一个参数,当您使用 trailing 闭包时,您甚至可以把 () 省略掉。
<p>注意:
如果函数只需要闭包表达式一个参数,当您使用尾随闭包时,您甚至可以把 () 省略掉。
NOTE</p>
</blockquote>
<p>在上例中作为 <code>sort</code> 函数参数的字符串排序闭包可以改写为:</p>
<p>在上例中作为<code>sort</code>函数参数的字符串排序闭包可以改写为:</p>
<pre><code>reversed = sort(names) { $0 &gt; $1 }
</code></pre><p>当闭包非常长以至于不能在一行中进行书写时,Trailing 闭包变得非常有用。
举例来说Swift 的 <strong>Array</strong> 类型有一个 <code>map</code> 方法,其获取一个闭包表达式作为其唯一参数。
</code></pre><p>当闭包非常长以至于不能在一行中进行书写时,尾随闭包变得非常有用。
举例来说Swift 的 <strong>Array</strong> 类型有一个<code>map</code>方法,其获取一个闭包表达式作为其唯一参数。
数组中的每一个元素调用一次该闭包函数,并返回该元素所映射的值(也可以是不同类型的值)。
具体的映射方式和返回值类型由闭包来指定。</p>
<p>当提供给数组闭包函数后,<code>map</code> 方法将返回一个新的数组,数组中包含了与原数组一一对应的映射后的值。</p>
<p>下例介绍了如何在 <code>map</code> 方法中使用 trailing 闭包将 <strong>Int</strong> 类型数组 <code>[16,58,510]</code> 转换为包含对应 <strong>String</strong> 类型的数组 <code>[&quot;OneSix&quot;, &quot;FiveEight&quot;, &quot;FiveOneZero&quot;]</code>:</p>
<p>当提供给数组闭包函数后,<code>map</code>方法将返回一个新的数组,数组中包含了与原数组一一对应的映射后的值。</p>
<p>下例介绍了如何在<code>map</code>方法中使用尾随闭包将 <strong>Int</strong> 类型数组<code>[16,58,510]</code>转换为包含对应 <strong>String</strong> 类型的数组<code>[&quot;OneSix&quot;, &quot;FiveEight&quot;, &quot;FiveOneZero&quot;]</code>:</p>
<pre><code>let digitNames = [
0: &quot;Zero&quot;, 1: &quot;One&quot;, 2: &quot;Two&quot;, 3: &quot;Three&quot;, 4: &quot;Four&quot;,
5: &quot;Five&quot;, 6: &quot;Six&quot;, 7: &quot;Seven&quot;, 8: &quot;Eight&quot;, 9: &quot;Nine&quot;
@ -724,8 +741,8 @@ NOTE</p>
let numbers = [16, 58, 510]
</code></pre><p>如上代码创建了一个数字位和他们名字映射的英文版本字典。
同时定义了一个准备转换为字符串的整型数组。</p>
<p>您现在可以通过传递一个 trailing 闭包给 <code>numbers</code><code>map</code> 方法来创建对应的字符串版本数组。
需要注意的时调用 <code>numbers.map</code> 不需要在 <code>map</code> 后面包含任何括号,因为其只需要传递闭包表达式这一个参数,并且该闭包表达式参数通过 trailing 方式进行撰写:</p>
<p>您现在可以通过传递一个尾随闭包给<code>numbers</code><code>map</code>方法来创建对应的字符串版本数组。
需要注意的时调用<code>numbers.map</code>不需要在<code>map</code>后面包含任何括号,因为其只需要传递闭包表达式这一个参数,并且该闭包表达式参数通过尾随方式进行撰写:</p>
<pre><code>let strings = numbers.map {
(var number) -&gt; String in
var output = &quot;&quot;
@ -737,34 +754,36 @@ let numbers = [16, 58, 510]
}
// strings 常量被推断为字符串类型数组,即 String[]
// 其值为 [&quot;OneSix&quot;, &quot;FiveEight&quot;, &quot;FiveOneZero&quot;]
</code></pre><p><code>map</code> 在数组中为每一个元素调用了闭包表达式。
您不需要指定闭包的输入参数 <code>number</code> 的类型,因为可以通过要映射的数组类型进行推断。</p>
<p>闭包 <code>number</code> 参数被声明为一个变量参数 (变量的具体描述请参看<a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Functions.html#//apple_ref/doc/uid/TP40014097-CH10-XID_224" target="_blank">Constant and Variable Parameters</a>),因此可以在闭包函数体内对其进行修改。
</code></pre><p><code>map</code>在数组中为每一个元素调用了闭包表达式。
您不需要指定闭包的输入参数<code>number</code>的类型,因为可以通过要映射的数组类型进行推断。</p>
<p>闭包<code>number</code>参数被声明为一个变量参数 (变量的具体描述请参看<a href="">Constant and Variable Parameters</a>(<strong>这里需要Closure Expression Syntax进行配合</strong>)),因此可以在闭包函数体内对其进行修改。
闭包表达式制定了返回类型为 <strong>String</strong>,以表明存储映射值的新数组类型为 <strong>String</strong></p>
<p>闭包表达式在每次被调用的时候创建了一个字符串并返回。
其使用求余运算符 (number % 10) 计算最后一位数字并利用 <code>digitNames</code> 字典获取所映射的字符串。</p>
其使用求余运算符 (number % 10) 计算最后一位数字并利用<code>digitNames</code>字典获取所映射的字符串。</p>
<blockquote>
<p>注意:</p>
<p>字典 <code>digitNames</code> 下标后跟着一个叹号 (!),因为字典下标返回一个可选值 (optional value),表明即使该 key 不存在也不会查找失败。
在上例中,它保证了 <code>number % 10</code> 可以总是作为一个 <code>digitNames</code> 字典的有效下标 key。
因此叹号可以用于强制展开 (force-unwrap) 存储在可选下标项中的 <strong>String</strong> 类型值。</p>
<p>注意:
字典<code>digitNames</code>下标后跟着一个叹号 (!),因为字典下标返回一个可选值 (optional value),表明即使该 key 不存在也不会查找失败。
在上例中,它保证了<code>number % 10</code>可以总是作为一个<code>digitNames</code>字典的有效下标 key。
因此叹号可以用于强制解析 (force-unwrap) 存储在可选下标项中的 <strong>String</strong> 类型值。</p>
</blockquote>
<p> <code>digitNames</code> 字典中获取的字符串被添加到输出的前部,逆序建立了一个字符串版本的数字。
(在表达式 <code>number % 10</code>如果number为16则返回658返回8510返回0)。</p>
<p><code>number</code> 变量之后除以10。
<p><code>digitNames</code>字典中获取的字符串被添加到输出的前部,逆序建立了一个字符串版本的数字。
(在表达式<code>number % 10</code>如果number为16则返回658返回8510返回0)。</p>
<p><code>number</code>变量之后除以10。
因为其是整数,在计算过程中未除尽部分被忽略。
因此 16变成了158变成了5510变成了51。</p>
<p>整个过程重复进行,直到 <code>number /= 10</code> 为0这时闭包会将字符串输出map函数则会将字符串添加到所映射的数组中。</p>
<p>上例中 trailing 闭包语法在函数后整洁封装了具体的闭包功能,而不再需要将整个闭包包裹在 <code>map</code> 函数的括号内。</p>
<h3 id="-caputure-">捕获 (Caputure)</h3>
<p>整个过程重复进行,直到<code>number /= 10</code>为0这时闭包会将字符串输出<code>map</code>函数则会将字符串添加到所映射的数组中。</p>
<p>上例中尾随闭包语法在函数后整洁封装了具体的闭包功能,而不再需要将整个闭包包裹在<code>map</code>函数的括号内。</p>
<p><a name="capturing_values"></a></p>
<h3 id="-capturing-values-">捕获值 (Capturing Values)</h3>
<hr>
<p>闭包可以在其定义的上下文中捕获常量或变量。
即使定义这些常量和变量的原域已经不存在,闭包仍然可以在闭包函数体内引用和修改这些值。</p>
<p>Swift最简单的闭包形式是嵌套函数也就是定义在其他函数的函数体内的函数。
嵌套函数可以捕获其外部函数所有的参数以及定义的常量和变量。</p>
<p>下例为一个叫做 <code>makeIncrementor</code> 的函数,其包含了一个叫做 <code>incrementor</code> 嵌套函数。
嵌套函数 <code>incrementor</code> 从上下文中捕获了两个值,<code>runningTotal</code><code>amount</code>
之后 <code>makeIncrementor</code><code>incrementor</code> 作为闭包返回。
每次调用 <code>incrementor</code> 时,其会以 <code>amount</code> 作为增量增加 <code>runningTotal</code> 的值。</p>
<p>下例为一个叫做<code>makeIncrementor</code>的函数,其包含了一个叫做<code>incrementor</code>嵌套函数。
嵌套函数<code>incrementor</code>从上下文中捕获了两个值,<code>runningTotal</code><code>amount</code>
之后<code>makeIncrementor</code><code>incrementor</code>作为闭包返回。
每次调用<code>incrementor</code>时,其会以<code>amount</code>作为增量增加<code>runningTotal</code>的值。</p>
<pre><code>func makeIncrementor(forIncrement amount: Int) -&gt; () -&gt; Int {
var runningTotal = 0
func incrementor() -&gt; Int {
@ -773,32 +792,32 @@ let numbers = [16, 58, 510]
}
return incrementor
}
</code></pre><p><code>makeIncrementor</code> 返回类型为 <code>() -&gt; Int</code>
</code></pre><p><code>makeIncrementor</code>返回类型为<code>() -&gt; Int</code>
这意味着其返回的是一个函数,而不是一个简单类型值。
该函数在每次调用时不接受参数只返回一个 <strong>Int</strong> 类型的值。
关于函数返回其他函数的内容,请查看<a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Functions.html#//apple_ref/doc/uid/TP40014097-CH10-XID_232" target="_blank">Function Types as Return Types</a></p>
<p><code>makeIncrementor</code> 函数定义了一个整型变量 <code>runningTotal</code> (初始为0) 用来存储当前跑步总数。
该值通过 <code>incrementor</code> 返回。</p>
<p><code>makeIncrementor</code> 有一个 <strong>Int</strong> 类型的参数,其外部命名为 <code>forIncrement</code> 内部命名为 <code>amount</code>,表示每次 <code>incrementor</code> 被调用时 <code>runningTotal</code> 将要增加的量。</p>
<p><code>incrementor</code> 函数用来执行实际的增加操作。
该函数简单地使 <code>runningTotal</code> 增加 <code>amount</code>,并将其返回。</p>
关于函数返回其他函数的内容,请查看<a href="">Function Types as Return Types</a>(<strong>需要函数章节进行配合</strong>)</p>
<p><code>makeIncrementor</code>函数定义了一个整型变量<code>runningTotal</code>(初始为0) 用来存储当前跑步总数。
该值通过<code>incrementor</code>返回。</p>
<p><code>makeIncrementor</code>有一个 <strong>Int</strong> 类型的参数,其外部命名为<code>forIncrement</code> 内部命名为<code>amount</code>,表示每次<code>incrementor</code>被调用时<code>runningTotal</code>将要增加的量。</p>
<p><code>incrementor</code>函数用来执行实际的增加操作。
该函数简单地使<code>runningTotal</code>增加<code>amount</code>,并将其返回。</p>
<p>如果我们单独看这个函数,会发现看上去不同寻常:</p>
<pre><code>func incrementor() -&gt; Int {
runningTotal += amount
return runningTotal
}
</code></pre><p><code>incrementor</code> 函数并没有获取任何参数,但是在函数体内访问了 <code>runningTotal</code><code>amount</code> 变量。这是因为其通过捕获在包含它的函数体内已经存在的 <code>runningTotal</code><code>amount</code> 变量而实现。</p>
<p>由于没有修改 <code>amount</code> 变量,<code>incrementor</code> 实际上捕获并存储了该变量的一个副本,而该副本随着 <code>incrementor</code> 一同被存储。</p>
<p>然而,因为每次调用该函数的时候都会修改 <code>runningTotal</code> 的值,<code>incrementor</code> 捕获了当前 <code>runningTotal</code> 变量的引用,而不是仅仅复制该变量的初始值。捕获一个引用保证了当 <code>makeIncrementor</code> 结束时候并不会消失,也保证了当下一次执行 <code>incrementor</code> 函数时,<code>runningTotal</code> 可以继续增加。</p>
</code></pre><p><code>incrementor</code>函数并没有获取任何参数,但是在函数体内访问了<code>runningTotal</code><code>amount</code>变量。这是因为其通过捕获在包含它的函数体内已经存在的<code>runningTotal</code><code>amount</code>变量而实现。</p>
<p>由于没有修改<code>amount</code>变量,<code>incrementor</code>实际上捕获并存储了该变量的一个副本,而该副本随着<code>incrementor</code>一同被存储。</p>
<p>然而,因为每次调用该函数的时候都会修改<code>runningTotal</code>的值,<code>incrementor</code>捕获了当前<code>runningTotal</code>变量的引用,而不是仅仅复制该变量的初始值。捕获一个引用保证了当<code>makeIncrementor</code>结束时候并不会消失,也保证了当下一次执行<code>incrementor</code>函数时,<code>runningTotal</code>可以继续增加。</p>
<blockquote>
<p>注意:</p>
<p>Swift 会决定捕获引用还是拷贝值。
您不需要标注 <code>amount</code> 或者 <code>runningTotal</code> 来声明在嵌入的 <code>incrementor</code> 函数中的使用方式。
Swift 同时也处理 <code>runingTotal</code> 变量的内存管理操作,如果不再被 <code>incrementor</code> 函数使用,则会被清除。</p>
<p>注意:
Swift 会决定捕获引用还是拷贝值。
您不需要标注<code>amount</code>或者<code>runningTotal</code>来声明在嵌入的<code>incrementor</code>函数中的使用方式。
Swift 同时也处理<code>runingTotal</code>变量的内存管理操作,如果不再被<code>incrementor</code>函数使用,则会被清除。</p>
</blockquote>
<p>下面为一个使用 <code>makeIncrementor</code> 的例子:</p>
<p>下面代码为一个使用<code>makeIncrementor</code>的例子:</p>
<pre><code>let incrementByTen = makeIncrementor(forIncrement: 10)
</code></pre><p>该例子定义了一个叫做 <code>incrementByTen</code> 的常量该常量指向一个每次调用会加10的 <code>incrementor</code> 函数。
</code></pre><p>该例子定义了一个叫做<code>incrementByTen</code>的常量该常量指向一个每次调用会加10的<code>incrementor</code>函数。
调用这个函数多次可以得到以下结果:</p>
<pre><code>incrementByTen()
// 返回的值为10
@ -806,23 +825,25 @@ incrementByTen()
// 返回的值为20
incrementByTen()
// 返回的值为30
</code></pre><p>如果您创建了另一个 <code>incrementor</code>,其会有一个属于自己的独立的 <code>runningTotal</code> 变量的引用。
下面的例子中,<code>incrementBySevne</code> 捕获了一个新的 <code>runningTotal</code> 变量,该变量和 <code>incrementByTen</code> 中捕获的变量没有任何联系:</p>
</code></pre><p>如果您创建了另一个<code>incrementor</code>,其会有一个属于自己的独立的<code>runningTotal</code>变量的引用。
下面的例子中,<code>incrementBySevne</code>捕获了一个新的<code>runningTotal</code>变量,该变量和<code>incrementByTen</code>中捕获的变量没有任何联系:</p>
<pre><code>let incrementBySeven = makeIncrementor(forIncrement: 7)
incrementBySeven()
// 返回的值为7
incrementByTen()
// 返回的值为40
</code></pre><blockquote>
<p>注意:</p>
<p>如果您闭包分配给一个类实例的属性,并且该闭包通过指向该实例或其成员来捕获了该实例,您将创建一个在闭包和实例间的强引用环。
Swift 使用捕获列表来打破这种强引用环。更多信息,请参考 <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/AutomaticReferenceCounting.html#//apple_ref/doc/uid/TP40014097-CH20-XID_61" target="_blank">Strong Reference Cycles for Closures</a></p>
<p>注意:
如果您闭包分配给一个类实例的属性,并且该闭包通过指向该实例或其成员来捕获了该实例,您将创建一个在闭包和实例间的强引用环。
Swift 使用捕获列表来打破这种强引用环。更多信息,请参考 <a href="">Strong Reference Cycles for Closures</a>(<strong>需要ARC章节进行配合</strong>)</p>
</blockquote>
<p><a name="closures_are_reference_types"></a></p>
<h3 id="-">闭包是引用类型</h3>
<p>上面的例子中,<code>incrementBySeven</code><code>incrementByTen</code> 是常量,但是这些常量指向的闭包仍然可以增加其捕获的变量值。
<hr>
<p>上面的例子中,<code>incrementBySeven</code><code>incrementByTen</code>是常量,但是这些常量指向的闭包仍然可以增加其捕获的变量值。
这是因为函数和闭包都是引用类型。</p>
<p>无论您将函数/闭包赋值给一个常量还是变量,您实际上都是将常量/变量的值设置为对应函数/闭包的引用。
上面的例子中,<code>incrementByTen</code> 指向闭包的引用是一个常量,而并非闭包内容本身。</p>
上面的例子中,<code>incrementByTen</code>指向闭包的引用是一个常量,而并非闭包内容本身。</p>
<p>这也意味着如果您将闭包赋值给了两个不同的常量/变量,两个值都会指向同一个闭包:</p>
<pre><code>let alsoIncrementByTen = incrementByTen
alsoIncrementByTen()

View File

@ -46,7 +46,7 @@
<div class="book" data-level="2.8" data-basepath=".." data-revision="1402377857835">
<div class="book" data-level="2.8" data-basepath=".." data-revision="1402386668059">
<div class="book-header">
<!-- Actions Left -->
<a href="#" class="btn pull-left toggle-summary" aria-label="Toggle summary"><i class="fa fa-align-justify"></i></a>
@ -587,7 +587,7 @@
<div class="page-inner">
<section class="normal" id="section-gitbook_25">
<section class="normal" id="section-gitbook_412">
<h1 id="-">枚举</h1>
<p>本页内容包含:</p>

View File

@ -46,7 +46,7 @@
<div class="book" data-level="2.9" data-basepath=".." data-revision="1402377857835">
<div class="book" data-level="2.9" data-basepath=".." data-revision="1402386668059">
<div class="book-header">
<!-- Actions Left -->
<a href="#" class="btn pull-left toggle-summary" aria-label="Toggle summary"><i class="fa fa-align-justify"></i></a>
@ -587,7 +587,7 @@
<div class="page-inner">
<section class="normal" id="section-gitbook_26">
<section class="normal" id="section-gitbook_413">
<h3 id="-">类和结构体</h3>
<p>本页包含内容:</p>

View File

@ -46,7 +46,7 @@
<div class="book" data-level="2.10" data-basepath=".." data-revision="1402377857835">
<div class="book" data-level="2.10" data-basepath=".." data-revision="1402386668059">
<div class="book-header">
<!-- Actions Left -->
<a href="#" class="btn pull-left toggle-summary" aria-label="Toggle summary"><i class="fa fa-align-justify"></i></a>
@ -587,7 +587,7 @@
<div class="page-inner">
<section class="normal" id="section-gitbook_27">
<section class="normal" id="section-gitbook_414">
<h1 id="-properties-">属性 (Properties)</h1>
<p><strong>属性</strong>将值跟特定的类、结构或枚举关联。一种是存储属性,把常量或变量的值作为实例的一部分,一种是计算属性,它计算一个值。计算属性可以用于类、结构和枚举里,存储属性只能用于类和结构。</p>
@ -595,7 +595,7 @@
<p>另外,还可以定义属性监视器来监控属性值的变化,以此来触发一个自定义的操作。属性监视器可以添加到自己写的存储属性上,也可以添加到从父类继承的属性上。</p>
<h2 id="-">存储属性</h2>
<p>简单来说,一个存储属性就是一个特定类型实例里表示常量或变量的部分,存储属性可以是<em>变量存储属性</em>(用关键字<code>var</code>定义),也可以是<em>常量存储属性</em>(用关键字<code>let</code>定义)。</p>
<p>可以在定义存储属性的时候指定默认值,详见<a href="#">默认属性值</a>一节。也可以在初始化阶段设置或修改存储属性的值,甚至修改常量存储属性的值,详见<a href="#">在初始化阶段修改常量存储属性</a>一节。</p>
<p>可以在定义存储属性的时候指定默认值,详见<a href="chapter2/14_Initialization.md#">默认属性值</a>一节。也可以在初始化阶段设置或修改存储属性的值,甚至修改常量存储属性的值,详见<a href="chapter2/14_Initialization.md#">在初始化阶段修改常量存储属性</a>一节。</p>
<p>下面的例子定义了一个名为<code>FixedLengthRange</code>的结构体,表示一个在创建后无法修改整数范围的类型:</p>
<pre><code>struct FixedLengthRange {
var firstValue: Int
@ -605,7 +605,7 @@ var rangeOfThreeItems = FixedLengthRange(firstValue: 0, length: 3)
// the range represents integer values 0, 1, and 2
rangeOfThreeItems.firstValue = 6
// the range now represents integer values 6, 7, and 8
</code></pre><p><code>FixedLengthRange</code>的实例包含一个名为<code>firstValue</code>的变量存储属性和一个名为<code>length</code>的常量存储属性。在上面的例子中,<code>length</code>在创建实例的时候被赋值,因为它是一个常量存储属性,所以无法修改它的值。</p>
</code></pre><p><code>FixedLengthRange</code>的实例包含一个名为<code>firstValue</code>的变量存储属性和一个名为<code>length</code>的常量存储属性。在上面的例子中,<code>length</code>在创建实例的时候被赋值,因为它是一个常量存储属性,所以无法修改它的值。</p>
<h3 id="-">常量和存储属性</h3>
<p>如果创建了一个结构体的实例并赋值给一个常量,则无法修改实例的任何属性,即使定义了变量存储属性:</p>
<pre><code>let rangeOfFourItems = FixedLengthRange(firstValue: 0, length: 4)
@ -615,6 +615,7 @@ rangeOfFourItems.firstValue = 6
</code></pre><p>因为<code>rangeOfFourItems</code>声明成了常量(用<code>let</code>关键字),即使<code>firstValue</code>是一个变量属性,也无法再修改属性它的值。</p>
<p>这种行为是由于结构体struct属于<em>值类型</em>。当值类型的实例被声明为常量的时候,它的所有属性也就成了常量。</p>
<p>属于<em>引用类型</em>的类class则不一样把一个引用类型的实例赋给一个常量后仍然可以修改实例的变量属性。</p>
<p><a name="lazy_stored_properties"></a></p>
<h3 id="-">延迟存储属性</h3>
<p>延迟存储属性是指当第一次被调用的时候才有初始值的属性。在属性声明前使用<code>@lazy</code>特性来表示一个延迟存储属性。</p>
<blockquote>
@ -650,11 +651,11 @@ manager.data += &quot;Some more data&quot;
// the DataImporter instance for the importer property has now been created
// prints &quot;data.txt”
</code></pre><h3 id="-">存储属性和实例变量</h3>
<p>如果您有过Objective-C经验应该知道有2种方式在类实例存储值和引用。对于属性来说,也可以使用实例变量作为属性值的后端存储。</p>
<p>Swift编程语言中把这些理论统一用属性来实现。Swift中的属性没有对应的实例变量属性的后端存储也无法直接访问。这就避免了不同场景下访问方式的困扰同时也将属性的定义简化成一个语句。
<p>如果您有过 Objective-C 经验,应该知道有种方式在类实例存储值和引用。对于属性来说,也可以使用实例变量作为属性值的后端存储。</p>
<p>Swift 编程语言中把这些理论统一用属性来实现。Swift 中的属性没有对应的实例变量,属性的后端存储也无法直接访问。这就避免了不同场景下访问方式的困扰,同时也将属性的定义简化成一个语句。
一个类型中属性的全部信息——包括命名、类型和内存管理特征——都在唯一一个地方定义。</p>
<h2 id="-">计算属性</h2>
<p>除存储属性外,类、结构体和枚举可以定义<em>计算属性</em>计算属性不直接存储值而是提供一个getter来获取值一个可选的setter来间接设置其他属性或变量的值。</p>
<p>除存储属性外,类、结构体和枚举可以定义<em>计算属性</em>,计算属性不直接存储值,而是提供一个 getter 来获取值,一个可选的 setter 来间接设置其他属性或变量的值。</p>
<pre><code>struct Point {
var x = 0.0, y = 0.0
}
@ -682,7 +683,7 @@ let initialSquareCenter = square.center
square.center = Point(x: 15.0, y: 15.0)
println(&quot;square.origin is now at (\(square.origin.x), \(square.origin.y))&quot;)
// prints &quot;square.origin is now at (10.0, 10.0)”
</code></pre><p>这个例子定义了3个几何形状的结构体:</p>
</code></pre><p>这个例子定义了 3 个几何形状的结构体:</p>
<ul>
<li><code>Point</code>封装了一个<code>(x, y)</code>的坐标</li>
<li><code>Size</code>封装了一个<code>width</code><code>height</code></li>
@ -693,8 +694,8 @@ println(&quot;square.origin is now at (\(square.origin.x), \(square.origin.y))&q
<p><code>square</code><code>center</code>属性可以通过点运算符(<code>square.center</code>来访问这会调用getter来获取属性的值。跟直接返回已经存在的值不同getter实际上通过计算然后返回一个新的<code>Point</code>实例表示<code>square</code>的中心点。如代码所示,它正确返回了中心点<code>(5, 5)</code></p>
<p><code>center</code>属性之后被设置了一个新的值<code>(15, 15)</code>,表示向右上方移动正方形到如图所示橙色正方形的位置。设置属性<code>center</code>的值会调用setter来修改属性<code>origin</code><code>x</code><code>y</code>的值,从而实现移动正方形到新的位置。</p>
<p><img src="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/computedProperties_2x.png" alt="Computed Properties sample" width="388" height="387" /></p>
<h3 id="-setter-">便捷Setter声明</h3>
<p>如果计算属性的setter没有定义表示新值的参数名则可以使用默认名称<code>newValue</code>。下面是使用了便捷Setter声明的<code>Rect</code>结构体代码:</p>
<h3 id="-setter-">便捷 setter 声明</h3>
<p>如果计算属性的 setter 没有定义表示新值的参数名,则可以使用默认名称<code>newValue</code>。下面是使用了便捷 setter 声明的<code>Rect</code>结构体代码:</p>
<pre><code>struct AlternativeRect {
var origin = Point()
var size = Size()
@ -711,7 +712,7 @@ println(&quot;square.origin is now at (\(square.origin.x), \(square.origin.y))&q
}
}
</code></pre><h3 id="-">只读计算属性</h3>
<p>只有getter没有setter的计算属性就是<em>只读计算属性</em>。只读计算属性总是返回一个值,可以通过点运算符访问,但不能设置新的值。</p>
<p>只有 getter 没有 setter 的计算属性就是<em>只读计算属性</em>。只读计算属性总是返回一个值,可以通过点运算符访问,但不能设置新的值。</p>
<blockquote>
<p>注意</p>
<p>必须使用<code>var</code>关键字定义计算属性,包括只读计算属性,因为他们的值不是固定的。<code>let</code>关键字只用来声明常量属性,表示初始化后再也无法修改的值。</p>
@ -730,10 +731,10 @@ println(&quot;the volume of fourByFiveByTwo is \(fourByFiveByTwo.volume)&quot;)
<p>尽管如此,<code>Cuboid</code>提供一个只读计算属性来让外部用户直接获取体积是很有用的。</p>
<h2 id="-">属性监视器</h2>
<p><em>属性监视器</em>监控和响应属性值的变化,每次属性被设置值的时候都会调用属性监视器,甚至新的值和现在的值相同的时候也不例外。</p>
<p>可以为除了延迟存储属性之外的其他存储属性添加属性监视器,也可以通过重载属性的方式为继承的属性(包括存储属性和计算属性)添加属性监视器。属性重载详见<a href="#">重载</a>一节。</p>
<p>可以为除了延迟存储属性之外的其他存储属性添加属性监视器,也可以通过重载属性的方式为继承的属性(包括存储属性和计算属性)添加属性监视器。属性重载详见<a href="chapter/13_Inheritance.md#">重载</a>一节。</p>
<blockquote>
<p>注意</p>
<p>不需要为无法重载的计算属性添加属性监视器因为可以通过setter直接监控和响应值的变化。</p>
<p>不需要为无法重载的计算属性添加属性监视器,因为可以通过 setter 直接监控和响应值的变化。</p>
</blockquote>
<p>可以为属性添加如下的一个或全部监视器:</p>
<ul>
@ -783,7 +784,7 @@ stepCounter.totalSteps = 896
<p>另外,在全局或局部范围都可以定义计算型变量和为存储型变量定义监视器,计算型变量跟计算属性一样,返回一个计算的值而不是存储值,声明格式也完全一样。</p>
<blockquote>
<p>注意</p>
<p>全局的常量或变量都是延迟计算的,跟<a href="#">延迟存储属性</a>相似,不同的地方在于,全局的常量或变量不需要标记<code>@lazy</code>特性。</p>
<p>全局的常量或变量都是延迟计算的,跟<a href="#lazy_stored_properties">延迟存储属性</a>相似,不同的地方在于,全局的常量或变量不需要标记<code>@lazy</code>特性。</p>
<p>局部范围的常量或变量不会延迟计算。</p>
</blockquote>
<h2 id="-">类属性</h2>
@ -877,8 +878,7 @@ println(rightChannel.currentLevel)
// prints &quot;10&quot;
println(AudioChannel.maxInputLevelForAllChannels)
// prints &quot;10”
</code></pre><p>[本章完]</p>
</code></pre>
</section>

View File

@ -46,7 +46,7 @@
<div class="book" data-level="2.11" data-basepath=".." data-revision="1402377857835">
<div class="book" data-level="2.11" data-basepath=".." data-revision="1402386668059">
<div class="book-header">
<!-- Actions Left -->
<a href="#" class="btn pull-left toggle-summary" aria-label="Toggle summary"><i class="fa fa-align-justify"></i></a>
@ -587,7 +587,7 @@
<div class="page-inner">
<section class="normal" id="section-gitbook_28">
<section class="normal" id="section-gitbook_415">
<h1 id="-methods-">方法(Methods)</h1>
<p><strong>方法</strong>是与某些特定类型相关联的功能/函数。类、结构体、枚举都可以定义实例方法;实例方法为指定类型的实例封装了特定的任务与功能。类、结构体、枚举也可以定义类(型)方法(type itself)类型方法与类型自身相关联。类型方法与Objective-C中的类方法(class methods)相似。</p>

View File

@ -46,7 +46,7 @@
<div class="book" data-level="2.12" data-basepath=".." data-revision="1402377857835">
<div class="book" data-level="2.12" data-basepath=".." data-revision="1402386668059">
<div class="book-header">
<!-- Actions Left -->
<a href="#" class="btn pull-left toggle-summary" aria-label="Toggle summary"><i class="fa fa-align-justify"></i></a>
@ -587,7 +587,7 @@
<div class="page-inner">
<section class="normal" id="section-gitbook_29">
<section class="normal" id="section-gitbook_416">
<h1 id="-subscripts-">下标 (Subscripts)</h1>
<p>下标可以定义在类(Class)、结构体(structures)和枚举(enumerations)这些目标中,可以认为是访问对象、集合或序列的快捷方式。举例来说,用下标访问一个数组(Array)实例中的元素可以这样写 <code>someArray[index]</code> ,访问字典(Dictionary)实例中的元素可以这样写 <code>someDictionary[key]</code>,而不需要再调用实例的某个方法来获得元素的值。</p>

View File

@ -46,7 +46,7 @@
<div class="book" data-level="2.13" data-basepath=".." data-revision="1402377857835">
<div class="book" data-level="2.13" data-basepath=".." data-revision="1402386668059">
<div class="book-header">
<!-- Actions Left -->
<a href="#" class="btn pull-left toggle-summary" aria-label="Toggle summary"><i class="fa fa-align-justify"></i></a>
@ -587,7 +587,7 @@
<div class="page-inner">
<section class="normal" id="section-gitbook_7">
<section class="normal" id="section-gitbook_389">
<h1 id="-">继承</h1>
<p>一个类可以继承另一个类的方法属性和其它特性。当一个类继承其它类继承类叫子类被继承类叫超类或父类。在Swift中继承是区分「类」与其它类型的一个基本特征。</p>

View File

@ -46,7 +46,7 @@
<div class="book" data-level="2.14" data-basepath=".." data-revision="1402377857835">
<div class="book" data-level="2.14" data-basepath=".." data-revision="1402386668059">
<div class="book-header">
<!-- Actions Left -->
<a href="#" class="btn pull-left toggle-summary" aria-label="Toggle summary"><i class="fa fa-align-justify"></i></a>

View File

@ -46,7 +46,7 @@
<div class="book" data-level="2.15" data-basepath=".." data-revision="1402377857835">
<div class="book" data-level="2.15" data-basepath=".." data-revision="1402386668059">
<div class="book-header">
<!-- Actions Left -->
<a href="#" class="btn pull-left toggle-summary" aria-label="Toggle summary"><i class="fa fa-align-justify"></i></a>
@ -587,7 +587,7 @@
<div class="page-inner">
<section class="normal" id="section-gitbook_32">
<section class="normal" id="section-gitbook_419">
<h1 id="-">析构过程</h1>
<p>在一个类的实例被释放之前析构函数被立即调用。用关键字deinit来标示析构函数类似于初始化函数用init来标示。析构函数只适用于类类型。</p>

View File

@ -46,7 +46,7 @@
<div class="book" data-level="2.16" data-basepath=".." data-revision="1402377857835">
<div class="book" data-level="2.16" data-basepath=".." data-revision="1402386668059">
<div class="book-header">
<!-- Actions Left -->
<a href="#" class="btn pull-left toggle-summary" aria-label="Toggle summary"><i class="fa fa-align-justify"></i></a>
@ -587,7 +587,7 @@
<div class="page-inner">
<section class="normal" id="section-gitbook_33">
<section class="normal" id="section-gitbook_420">
<h1 id="-">自动引用计数</h1>
<p>本页包含内容:</p>

View File

@ -46,7 +46,7 @@
<div class="book" data-level="2.17" data-basepath=".." data-revision="1402377857835">
<div class="book" data-level="2.17" data-basepath=".." data-revision="1402386668059">
<div class="book-header">
<!-- Actions Left -->
<a href="#" class="btn pull-left toggle-summary" aria-label="Toggle summary"><i class="fa fa-align-justify"></i></a>
@ -587,7 +587,7 @@
<div class="page-inner">
<section class="normal" id="section-gitbook_34">
<section class="normal" id="section-gitbook_421">
<h1 id="optional-chaining">Optional Chaining</h1>
<p>可选链Optional Chaining是一种可以请求和调用属性、方法及子脚本的过程它的自判断性体现于请求或调用的目标当前可能为空<code>nil</code>)。如果自判断的目标有值,那么调用就会成功;相反,如果选择的目标为空(<code>nil</code>),则这种调用将返回空(<code>nil</code>)。多次请求或调用可以被链接在一起形成一个链,如果任何一个节点为空(<code>nil</code>)将导致整个链失效。</p>

View File

@ -46,7 +46,7 @@
<div class="book" data-level="2.18" data-basepath=".." data-revision="1402377857835">
<div class="book" data-level="2.18" data-basepath=".." data-revision="1402386668059">
<div class="book-header">
<!-- Actions Left -->
<a href="#" class="btn pull-left toggle-summary" aria-label="Toggle summary"><i class="fa fa-align-justify"></i></a>
@ -587,7 +587,7 @@
<div class="page-inner">
<section class="normal" id="section-gitbook_36">
<section class="normal" id="section-gitbook_422">
<h1 id="-type-casting-">类型检查Type Casting</h1>
<p>ps为了方便各位检验所以保留了英文可删。

View File

@ -46,7 +46,7 @@
<div class="book" data-level="2.19" data-basepath=".." data-revision="1402377857835">
<div class="book" data-level="2.19" data-basepath=".." data-revision="1402386668059">
<div class="book-header">
<!-- Actions Left -->
<a href="#" class="btn pull-left toggle-summary" aria-label="Toggle summary"><i class="fa fa-align-justify"></i></a>
@ -587,7 +587,7 @@
<div class="page-inner">
<section class="normal" id="section-gitbook_35">
<section class="normal" id="section-gitbook_423">
<h1 id="-">类型嵌套</h1>
<p>本页包含内容:</p>

View File

@ -46,7 +46,7 @@
<div class="book" data-level="2.20" data-basepath=".." data-revision="1402377857835">
<div class="book" data-level="2.20" data-basepath=".." data-revision="1402386668059">
<div class="book-header">
<!-- Actions Left -->
<a href="#" class="btn pull-left toggle-summary" aria-label="Toggle summary"><i class="fa fa-align-justify"></i></a>
@ -587,7 +587,7 @@
<div class="page-inner">
<section class="normal" id="section-gitbook_37">
<section class="normal" id="section-gitbook_424">
<h1 id="-extensions-">扩展Extensions</h1>
<hr>

View File

@ -46,7 +46,7 @@
<div class="book" data-level="2.21" data-basepath=".." data-revision="1402377857835">
<div class="book" data-level="2.21" data-basepath=".." data-revision="1402386668059">
<div class="book-header">
<!-- Actions Left -->
<a href="#" class="btn pull-left toggle-summary" aria-label="Toggle summary"><i class="fa fa-align-justify"></i></a>
@ -587,7 +587,7 @@
<div class="page-inner">
<section class="normal" id="section-gitbook_39">
<section class="normal" id="section-gitbook_429">
<h1 id="-">协议</h1>
<p><code>Protocol(协议)</code>用于<strong>统一</strong>方法和属性的名称,而不实现任何功能,(<em>译者注: 协议在其他语言中也称作<code>接口(Interface)</code></em>).<code>协议</code>能够被<code></code>,<code>枚举</code>,<code>结构体</code>实现,满足协议要求的<code></code>,<code>枚举</code>,<code>结构体</code>被称为协议的<code>遵循者</code>.</p>

View File

@ -46,7 +46,7 @@
<div class="book" data-level="2.22" data-basepath=".." data-revision="1402377857835">
<div class="book" data-level="2.22" data-basepath=".." data-revision="1402386668059">
<div class="book-header">
<!-- Actions Left -->
<a href="#" class="btn pull-left toggle-summary" aria-label="Toggle summary"><i class="fa fa-align-justify"></i></a>
@ -587,7 +587,7 @@
<div class="page-inner">
<section class="normal" id="section-gitbook_40">
<section class="normal" id="section-gitbook_426">
<h1 id="-">泛型</h1>
<hr>

View File

@ -46,7 +46,7 @@
<div class="book" data-level="2.23" data-basepath=".." data-revision="1402377857835">
<div class="book" data-level="2.23" data-basepath=".." data-revision="1402386668059">
<div class="book-header">
<!-- Actions Left -->
<a href="#" class="btn pull-left toggle-summary" aria-label="Toggle summary"><i class="fa fa-align-justify"></i></a>

View File

@ -46,7 +46,7 @@
<div class="book" data-level="2" data-basepath=".." data-revision="1402377857835">
<div class="book" data-level="2" data-basepath=".." data-revision="1402386668059">
<div class="book-header">
<!-- Actions Left -->
<a href="#" class="btn pull-left toggle-summary" aria-label="Toggle summary"><i class="fa fa-align-justify"></i></a>
@ -587,7 +587,7 @@
<div class="page-inner">
<section class="normal" id="section-gitbook_44">
<section class="normal" id="section-gitbook_431">
<h1 id="swift-">Swift 教程</h1>
<p>本章介绍了 Swift 的各种特性及其使用方法,是全书的核心部分。</p>

View File

@ -46,7 +46,7 @@
<div class="book" data-level="3.1" data-basepath=".." data-revision="1402377857835">
<div class="book" data-level="3.1" data-basepath=".." data-revision="1402386668059">
<div class="book-header">
<!-- Actions Left -->
<a href="#" class="btn pull-left toggle-summary" aria-label="Toggle summary"><i class="fa fa-align-justify"></i></a>
@ -587,7 +587,7 @@
<div class="page-inner">
<section class="normal" id="section-gitbook_46">
<section class="normal" id="section-gitbook_433">
<h1 id="-">关于语言附注</h1>
<p>本书的这一节描述了Swift编程语言的形式语法。这里描述的语法是为了帮助您更详细的了解该语言而不是让您直接实现一个解析器或编译器。</p>

View File

@ -46,7 +46,7 @@
<div class="book" data-level="3.2" data-basepath=".." data-revision="1402377857835">
<div class="book" data-level="3.2" data-basepath=".." data-revision="1402386668059">
<div class="book-header">
<!-- Actions Left -->
<a href="#" class="btn pull-left toggle-summary" aria-label="Toggle summary"><i class="fa fa-align-justify"></i></a>
@ -587,7 +587,7 @@
<div class="page-inner">
<section class="normal" id="section-gitbook_51">
<section class="normal" id="section-gitbook_439">
<h1 id="-">语法结构</h1>
<p>本页包含内容:</p>

View File

@ -46,7 +46,7 @@
<div class="book" data-level="3.3" data-basepath=".." data-revision="1402377857835">
<div class="book" data-level="3.3" data-basepath=".." data-revision="1402386668059">
<div class="book-header">
<!-- Actions Left -->
<a href="#" class="btn pull-left toggle-summary" aria-label="Toggle summary"><i class="fa fa-align-justify"></i></a>
@ -587,7 +587,7 @@
<div class="page-inner">
<section class="normal" id="section-gitbook_47">
<section class="normal" id="section-gitbook_434">
<h1 id="-types-">类型Types</h1>
<hr>

View File

@ -46,7 +46,7 @@
<div class="book" data-level="3.4" data-basepath=".." data-revision="1402377857835">
<div class="book" data-level="3.4" data-basepath=".." data-revision="1402386668059">
<div class="book-header">
<!-- Actions Left -->
<a href="#" class="btn pull-left toggle-summary" aria-label="Toggle summary"><i class="fa fa-align-justify"></i></a>
@ -587,6 +587,562 @@
<div class="page-inner">
<section class="normal" id="section-gitbook_436">
<h1 id="-expressions-">表达式(Expressions)</h1>
<hr>
<p>Swift 中存在四种表达式: 前缀(prefix)表达式,二元(binary)表达式,主要(primary)表达式和后缀(postfix)表达式。表达式可以返回一个值,以及运行某些逻辑(causes a side effect)。</p>
<p>前缀表达式和二元表达式就是对某些表达式使用各种运算符(operators)。 主要表达式是最短小的表达式,它提供了获取(变量的)值的一种途径。 后缀表达式则允许你建立复杂的表达式,例如配合函数调用和成员访问。 每种表达式都在下面有详细论述~</p>
<blockquote>
<p>表达式的语法</p>
<p><em>expression</em><em>prefix-expression</em>­<em>binary-expressions</em>(opt)
<em>expression-list</em><em>expression</em>­| <em>expression</em>­,­<em>expression-list</em></p>
</blockquote>
<h2 id="-prefix-expressions-">前缀表达式(Prefix Expressions)</h2>
<p>前缀表达式由 前缀符号和表达式组成。(这个前缀符号只能接收一个参数)</p>
<p>Swift 标准库支持如下的前缀操作符:</p>
<ul>
<li>++ 自增1 (increment)</li>
<li>-- 自减1 (decrement)</li>
<li>! 逻辑否 (Logical NOT )</li>
<li>~ 按位否 (Bitwise NOT )</li>
<li>+ 加(Unary plus)</li>
<li>- 减(Unary minus)</li>
</ul>
<p>对于这些操作符的使用,请参见: Basic Operators and Advanced Operators</p>
<p>作为对上面标准库运算符的补充,你也可以对 某个函数的参数使用 &#39;&amp;&#39;运算符。 更多信息,请参见: &quot;In-Out parameters&quot;.</p>
<blockquote>
<p>前缀表达式的语法</p>
<p><em>prefix-expression</em><em>prefix-operator</em> (opt) <em>postfix-expression</em>
<em>prefix-expression</em><em>in-out-expression</em>­
<em>in-out-expression</em>&amp;­<em>identifier</em>­</p>
</blockquote>
<h2 id="-binary-expressions-">二元表达式( Binary Expressions)</h2>
<p>二元表达式由 &quot;左边参数&quot; + &quot;二元运算符&quot; + &quot;右边参数&quot; 组成, 它有如下的形式:</p>
<p> <code>left-hand argument</code> <code>operator</code> <code>right-hand argument</code></p>
<p>Swift 标准库提供了如下的二元运算符:</p>
<ul>
<li>求幂相关无结合优先级160<ul>
<li>&lt;&lt; 按位左移(Bitwise left shift)</li>
<li><blockquote>
<blockquote>
<p>按位右移(Bitwise right shift)</p>
</blockquote>
</blockquote>
</li>
</ul>
</li>
<li>乘除法相关左结合优先级150<ul>
<li>* 乘</li>
<li>/ 除</li>
<li>% 求余</li>
<li>&amp;* 乘法,忽略溢出( Multiply, ignoring overflow)</li>
<li>&amp;/ 除法,忽略溢出(Divide, ignoring overflow)</li>
<li>&amp;% 求余, 忽略溢出( Remainder, ignoring overflow)</li>
<li>&amp; 位与( Bitwise AND)</li>
</ul>
</li>
<li>加减法相关(左结合, 优先级140)<ul>
<li>+ 加</li>
<li>- 减</li>
<li>&amp;+ Add with overflow</li>
<li>&amp;- Subtract with overflow</li>
<li>| 按位或(Bitwise OR )</li>
<li>^ 按位异或(Bitwise XOR)</li>
</ul>
</li>
<li>Range (无结合,优先级 135)<ul>
<li>.. 半闭值域 Half-closed range</li>
<li>... 全闭值域 Closed range</li>
</ul>
</li>
<li>类型转换 (无结合,优先级 132)<ul>
<li>is 类型检查( type check)</li>
<li>as 类型转换( type cast)</li>
</ul>
</li>
<li>Comparative (无结合,优先级 130)<ul>
<li>&lt; 小于</li>
<li>&lt;= 小于等于</li>
<li><blockquote>
<p>大于</p>
</blockquote>
</li>
<li><blockquote>
<p>= 大于等于</p>
</blockquote>
</li>
<li>== 等于</li>
<li>!= 不等</li>
<li>=== 恒等于</li>
<li>!== 不恒等</li>
<li>~= 模式匹配( Pattern match)</li>
</ul>
</li>
<li>合取( Conjunctive) (左结合,优先级 120)<ul>
<li>&amp;&amp; 逻辑与(Logical AND)</li>
</ul>
</li>
<li>析取(Disjunctive) (左结合,优先级 110)<ul>
<li>|| 逻辑或( Logical OR)</li>
</ul>
</li>
<li>三元条件(Ternary Conditional )(右结合,优先级 100)<ul>
<li>?: 三元条件 Ternary conditional</li>
</ul>
</li>
<li>赋值 (Assignment) (右结合, 优先级 90)<ul>
<li>= 赋值(Assign)</li>
<li>*= Multiply and assign</li>
<li>/= Divide and assign</li>
<li>%= Remainder and assign</li>
<li>+= Add and assign</li>
<li>-= Subtract and assign</li>
<li>&lt;&lt;= Left bit shift and assign</li>
<li><blockquote>
<blockquote>
<p>= Right bit shift and assign</p>
</blockquote>
</blockquote>
</li>
<li>&amp;= Bitwise AND and assign</li>
<li>^= Bitwise XOR and assign</li>
<li>|= Bitwise OR and assign</li>
<li>&amp;&amp;= Logical AND and assign</li>
<li>||= Logical OR and assign</li>
</ul>
</li>
</ul>
<p>关于这些运算符(operators)的更多信息请参见Basic Operators and Advanced Operators.</p>
<blockquote>
<blockquote>
<p>注意</p>
<p>在解析时, 一个二元表达式表示为一个一级数组(a flat list), 这个数组(List)根据运算符的先后顺序被转换成了一个tree. 例如: 2 + 3 <em> 5 首先被认为是: 2, + , <code>3</code>, </em>, 5. 随后它被转换成 tree (2 + (3 * 5))</p>
</blockquote>
<p>二元表达式的语法</p>
<p><em>binary-expression</em><em>binary-operator</em>­<em>prefix-expression</em>­
<em>binary-expression</em><em>assignment-operator</em>­prefix-expression<em>
</em>binary-expression<em></em>conditional-operator<em>­prefix-expression</em>
<em>binary-expression</em><em>type-casting-operator</em>­
<em>binary-expression</em>s → <em>binary-expression</em>­<em>binary-expressions</em>(opt­)</p>
</blockquote>
<h2 id="-assignment-operator-">赋值表达式( Assignment Operator)</h2>
<p>The assigment operator sets a new value for a given expression. It has the following form:
赋值表达式会对某个给定的表达式赋值。 它有如下的形式;</p>
<p><code>expression</code> = <code>value</code></p>
<p>就是把右边的 <em>value</em> 赋值给左边的 <em>expression</em>. 如果左边的<em>expression</em> 需要接收多个参数是一个tuple )那么右边必须也是一个具有同样数量参数的tuple. (允许嵌套的tuple)</p>
<pre><code class="lang-swift">(a, _, (b, c)) = (&quot;test&quot;, 9.45, (12, 3))
// a is &quot;test&quot;, b is 12, c is 3, and 9.45 is ignored
</code></pre>
<p>赋值运算符不返回任何值。</p>
<blockquote>
<p>赋值表达式的语法</p>
<p><em>assignment-operator</em> → =­</p>
</blockquote>
<h2 id="-ternary-conditional-operator-">三元条件运算符(Ternary Conditional Operator)</h2>
<p>三元条件运算符 是根据条件来获取值。 形式如下:</p>
<pre><code>`condition` ? `expression used if true` : `expression used if false`
</code></pre><p>如果 <code>condition</code> 是true, 那么返回 第一个表达式的值(此时不会调用第二个表达式), 否则返回第二个表达式的值(此时不会调用第一个表达式)。</p>
<p>想看三元条件运算符的例子,请参见: Ternary Conditional Operator.</p>
<blockquote>
<p>三元条件表达式</p>
<p><code>conditional-operator</code> → ?­<code>expression</code>­:­</p>
</blockquote>
<h2 id="-type-casting-operators-">类型转换运算符(Type-Casting Operators)</h2>
<p>有两种类型转换操作符: as 和 is. 它们有如下的形式:</p>
<pre><code>`expression` as `type`
`expression` as? `type`
`expression` is `type`
</code></pre><p>as 运算符会把<code>目标表达式</code>转换成指定的<code>类型</code>(specified type),过程如下:</p>
<ul>
<li><p>如果类型转换成功, 那么目标表达式就会返回指定类型的实例(instance). 例如:把子类(subclass)变成父类(superclass)时.</p>
</li>
<li><p>如果转换失败,则会抛出编译错误( compile-time error)。</p>
</li>
<li><p>如果上述两个情况都不是(也就是说,编译器在编译时期无法确定转换能否成功,) 那么目标表达式就会变成指定的类型的optional. (is an optional of the specified type ) 然后在运行时,如果转换成功, 目标表达式就会作为 optional的一部分来返回 否则目标表达式返回nil. 对应的例子是: 把一个 superclass 转换成一个 subclass.</p>
</li>
</ul>
<pre><code class="lang-swift">class SomeSuperType {}
class SomeType: SomeSuperType {}
class SomeChildType: SomeType {}
let s = SomeType()
let x = s as SomeSuperType // known to succeed; type is SomeSuperType
let y = s as Int // known to fail; compile-time error
let z = s as SomeChildType // might fail at runtime; type is SomeChildType?
</code></pre>
<p>使用&#39;as&#39;做类型转换跟正常的类型声明,对于编译器来说是一样的。例如:</p>
<pre><code class="lang-swift">let y1 = x as SomeType // Type information from &#39;as&#39;
let y2: SomeType = x // Type information from an annotation
</code></pre>
<p>&#39;is&#39; 运算符在“运行时(runtime)”会做检查。 成功会返回true, 否则 false</p>
<p>The check must not be known to be true or false at compile time. The following are invalid:
上述检查在“编译时(compile time)”不能使用。 例如下面的使用是错误的:</p>
<pre><code class="lang-swift">&quot;hello&quot; is String
&quot;hello&quot; is Int
</code></pre>
<p>关于类型转换的更多内容和例子,请参见: Type Casting.</p>
<blockquote>
<p>类型转换的语法</p>
<p><em>type-casting-operator</em> → is­<em>type</em>­| as­?(opt)­<em>type</em></p>
</blockquote>
<h2 id="-primary-expressions-">主要表达式(Primary Expressions)</h2>
<p><code>主要表达式</code>是最基本的表达式。 它们可以跟 前缀表达式,二元表达式,后缀表达式以及其他主要表达式组合使用。</p>
<blockquote>
<p>主要表达式的语法</p>
<p><em>primary-expression</em><em>identifier</em>­<em>generic-argument-clause</em>­(opt)
<em>primary-expression</em><em>literal-expression</em>­
<em>primary-expression</em><em>self-expression</em>­
<em>primary-expression</em><em>superclass-expression</em>­
<em>primary-expression</em><em>closure-expression</em>­
<em>primary-expression</em><em>parenthesized-expression</em>­
<em>primary-expression</em><em>implicit-member-expression</em>
<em>primary-expression</em><em>wildcard-expression</em></p>
</blockquote>
<h3 id="-literal-expression-">字符型表达式(Literal Expression)</h3>
<p>由这些内容组成普通的字符string, number) , 一个字符的字典或者数组,或者下面列表中的特殊字符。</p>
<table>
<thead>
<tr>
<th>字符(Literal)</th>
<th>类型(Type)</th>
<th>值(Value)</th>
</tr>
</thead>
<tbody>
<tr>
<td>_<em>FILE_</em></td>
<td>String</td>
<td>所在的文件名</td>
</tr>
<tr>
<td>_<em>LINE_</em></td>
<td>Int</td>
<td>所在的行数</td>
</tr>
<tr>
<td>_<em>COLUMN_</em></td>
<td>Int</td>
<td>所在的列数</td>
</tr>
<tr>
<td>_<em>FUNCTION_</em></td>
<td>String</td>
<td>所在的function 的名字</td>
</tr>
</tbody>
</table>
<p>在某个函数(function)中,<code>__FUNCTION__</code> 会返回当前函数的名字。 在某个方法(method)中,它会返回当前方法的名字。 在某个property 的getter/setter中会返回这个属性的名字。 在init/subscript中 只有的特殊成员(member)中会返回这个keyword的名字在某个文件的顶端(the top level of a file)它返回的是当前module的名字。</p>
<p>一个array literal是一个有序的值的集合。 它的形式是:</p>
<pre><code>[`value 1`, `value 2`, `...`]
</code></pre><p>数组中的最后一个表达式可以紧跟一个逗号(&#39;,&#39;). []表示空数组 。 array literal的type是 T[], 这个T就是数组中元素的type. 如果该数组中有多种type, T则是跟这些type的公共supertype最接近的type.(closest common supertype)</p>
<p>一个<code>dictionary literal</code> 是一个包含无序的键值对(key-value pairs)的集合,它的形式是:</p>
<pre><code>[`key 1`: `value 1`, `key 2`: `value 2`, `...`]
</code></pre><p>dictionary 的最后一个表达式可以是一个逗号(&#39;,&#39;). [:] 表示一个空的dictionary. 它的type是 Dictionary<KeyType, ValueType> (这里KeyType表示 key的type, ValueType表示 value的type) 如果这个dictionary 中包含多种 types, 那么KeyType, Value 则对应着它们的公共supertype最接近的type( closest common supertype).</p>
<blockquote>
<p>字符型表达式的语法</p>
<p><em>literal-expression</em><em>literal</em>
<em>literal-expression</em><em>array-literal</em>­| <em>dictionary-literal</em>­
<em>literal-expression</em><em>_<em>FILE_</em></em>­| <em>_<em>LINE_</em></em>­| <em>_<em>COLUMN_</em></em>­| <em>_<em>FUNCTION_</em></em>­
<em>array-literal</em> → [­<em>array-literal-items</em>­opt­]­
<em>array-literal-items</em><em>array-literal-item</em>­,­(opt) | ­<em>array-literal-item</em>­,­<em>array-literal-items</em>­
<em>array-literal-item</em><em>expression</em>­
<em>dictionary-literal</em> → [­<em>dictionary-literal-items</em>­]­ [­:­]­
<em>dictionary-literal-items</em><em>dictionary-literal-item</em>,­(opt)­| <em>dictionary-literal-item</em>­,­<em>dictionary-literal-items</em>­
<em>dictionary-literal-item</em><em>expression</em>­:­<em>expression</em>­</p>
</blockquote>
<h3 id="self-self-expression-">self表达式(Self Expression)</h3>
<p>self表达式是对 当前type 或者当前instance的引用。它的形式如下</p>
<blockquote>
<p>self
self.<code>member name</code>
self[<code>subscript index</code>]
self(<code>initializer arguments</code>)
self.init(<code>initializer arguments</code>)</p>
</blockquote>
<p>如果在 initializer, subscript, instance method中self等同于当前type的instance. 在一个静态方法(static method), 类方法(class method)中, self等同于当前的type.</p>
<p>当访问 member成员变量时 self 用来区分重名变量(例如函数的参数). 例如,
(下面的 self.greeting 指的是 var greeting: String, 而不是 init(greeting: String) )</p>
<pre><code class="lang-swift">class SomeClass {
var greeting: String
init(greeting: String) {
self.greeting = greeting
}
}
</code></pre>
<p>在mutating 方法中, 你可以使用self 对 该instance进行赋值。</p>
<pre><code class="lang-swift">struct Point {
var x = 0.0, y = 0.0
mutating func moveByX(deltaX: Double, y deltaY: Double) {
self = Point(x: x + deltaX, y: y + deltaY)
}
}
</code></pre>
<blockquote>
<p>self表达式的语法</p>
<p><em>self-expression</em> → self­
<em>self-expression</em> → self­.­<em>identifier</em>­
<em>self-expression</em> → self­[­<em>expression</em>­]­
<em>self-expression</em> → self­.­init­</p>
</blockquote>
<h3 id="-superclass-expression-">超类表达式(Superclass Expression)</h3>
<p>超类表达式可以使我们在某个class中访问它的超类. 它有如下形式:</p>
<pre><code>super.`member name`
super[`subscript index`]
super.init(`initializer arguments`)
</code></pre><p>形式1 用来访问超类的某个成员(member). 形式2 用来访问该超类的 subscript 实现。 形式3 用来访问该超类的 initializer.</p>
<p>子类(subclass)可以通过超类(superclass)表达式在它们的 member, subscripting 和 initializers 中来利用它们超类中的某些实现(既有的方法或者逻辑)。</p>
<blockquote>
<p>GRAMMAR OF A SUPERCLASS EXPRESSION</p>
<p><em>superclass-expression</em><em>superclass-method-expression</em> | <em>superclass-subscript-expression</em>­| <em>superclass-initializer-expression</em>
<em>superclass-method-expression</em> → super­.­<em>identifier</em>
<em>superclass-subscript-expression</em> → super­[­<em>expression</em>­]­
<em>superclass-initializer-expression</em> → super­.­init­</p>
</blockquote>
<h3 id="-closure-expression-">闭包表达式(Closure Expression)</h3>
<p>闭包(closure) 表达式可以建立一个闭包(在其他语言中也叫 lambda, 或者 匿名函数(anonymous function)). 跟函数(function)的声明一样, 闭包(closure)包含了可执行的代码(跟方法主体(statement)类似) 以及接收(capture)的参数。 它的形式如下:</p>
<pre><code class="lang-swift"> { (parameters) -&gt; return type in
statements
}
</code></pre>
<p>闭包的参数声明形式跟方法中的声明一样, 请参见Function Declaration.</p>
<p>闭包还有几种特殊的形式, 让使用更加简洁:</p>
<ul>
<li>闭包可以省略 它的参数的type 和返回值的type. 如果省略了参数和参数类型,就也要省略 &#39;in&#39;关键字。 如果被省略的type 无法被编译器获知(inferred) ,那么就会抛出编译错误。</li>
<li>闭包可以省略参数,转而在方法体(statement)中使用 $0, $1, $2 来引用出现的第一个,第二个,第三个参数。</li>
<li>如果闭包中只包含了一个表达式,那么该表达式就会自动成为该闭包的返回值。 在执行 &#39;type inference &#39;时,该表达式也会返回。</li>
</ul>
<p>下面几个 闭包表达式是 等价的:</p>
<pre><code class="lang-swift">myFunction {
(x: Int, y: Int) -&gt; Int in
return x + y
}
myFunction {
(x, y) in
return x + y
}
myFunction { return $0 + $1 }
myFunction { $0 + $1 }
</code></pre>
<p>关于 向闭包中传递参数的内容,参见: Function Call Expression.</p>
<p>闭包表达式可以通过一个参数列表(capture list) 来显式指定它需要的参数。 参数列表 由中括号 [] 括起来,里面的参数由逗号&#39;,&#39;分隔。一旦使用了参数列表,就必须使用&#39;in&#39;关键字(在任何情况下都得这样做包括忽略参数的名字type, 返回值时等等)。</p>
<p>在闭包的参数列表( capture list)中, 参数可以声明为 &#39;weak&#39; 或者 &#39;unowned&#39; .</p>
<pre><code class="lang-swift">myFunction { print(self.title) } // strong capture
myFunction { [weak self] in print(self!.title) } // weak capture
myFunction { [unowned self] in print(self.title) } // unowned capture
</code></pre>
<p>在参数列表中,也可以使用任意表达式来赋值. 该表达式会在 闭包被执行时赋值,然后按照不同的力度来获取(这句话请慎重理解)。(captured with the specified strength. ) 例如:</p>
<pre><code class="lang-swift">// Weak capture of &quot;self.parent&quot; as &quot;parent&quot;
myFunction { [weak parent = self.parent] in print(parent!.title) }
</code></pre>
<p>关于闭包表达式的更多信息和例子,请参见: Closure Expressions.</p>
<blockquote>
<p>闭包表达式的语法</p>
<p><em>closure-expression</em> → {­<em>closure-signature</em>­opt­<em>statements</em>­}­
<em>closure-signature</em><em>parameter-clause</em>­<em>function-result</em>­(opt)­in­
<em>closure-signature</em><em>identifier-list</em>­<em>function-result</em>­(opt)­in­
<em>closure-signature</em><em>capture-list</em>­<em>parameter-clause</em>­<em>function-result</em>­(opt)­in­
<em>closure-signature</em><em>capture-list</em>­<em>identifier-list</em>­<em>function-result</em>­(opt)­in­
<em>closure-signature</em><em>capture-list</em>­in­
<em>capture-list</em> → [­<em>capture-specifier</em>­<em>expression</em>­]­
<em>capture-specifier</em> → weak­| unowned­| unowned(safe)­| unowned(unsafe)­</p>
</blockquote>
<h3 id="-implicit-member-expression-">隐式成员表达式(Implicit Member Expression)</h3>
<p>在可以判断出类型(type)的上下文(context)中隐式成员表达式是访问某个type的member( 例如 class method, enumeration case) 的简洁方法。 它的形式是:</p>
<p>.<code>member name</code></p>
<p>例子:</p>
<pre><code class="lang-swift">var x = MyEnumeration.SomeValue
x = .AnotherValue
</code></pre>
<blockquote>
<p> 隐式成员表达式的语法</p>
<p> <em>implicit-member-expression</em> → .­<em>identifier</em></p>
</blockquote>
<h3 id="-parenthesized-expression-">圆括号表达式(Parenthesized Expression)</h3>
<p>圆括号表达式由多个子表达式和逗号&#39;,&#39;组成。 每个子表达式前面可以有 identifier x: 这样的可选前缀。形式如下:</p>
<p>(<code>identifier 1</code>: <code>expression 1</code>, <code>identifier 2</code>: <code>expression 2</code>, <code>...</code>)</p>
<p>圆括号表达式用来建立tuples 然后把它做为参数传递给 function. 如果某个圆括号表达式中只有一个 子表达式那么它的type就是 子表达式的type。例如 (1)的 type是Int, 而不是(Int)</p>
<blockquote>
<p>圆括号表达式的语法</p>
<p><em>parenthesized-expression</em> → (­<em>expression-element-list</em> (opt)­)­
<em>expression-element-list</em><em>expression-element</em>­| <em>expression-element</em>­,­<em>expression-element-list</em>­
<em>expression-element</em><em>expression</em>­| <em>identifier</em>­:­<em>expression</em></p>
</blockquote>
<h3 id="-wildcard-expression-">通配符表达式( Wildcard Expression)</h3>
<p>通配符表达式用来忽略传递进来的某个参数。例如下面的代码中10被传递给x, 20被忽略译注好奇葩的语法。。。</p>
<pre><code class="lang-swift">(x, _) = (10, 20)
// x is 10, 20 is ignored
</code></pre>
<blockquote>
<p>通配符表达式的语法</p>
<p><em>wildcard-expression</em> → _­</p>
</blockquote>
<h2 id="-postfix-expressions-">后缀表达式( Postfix Expressions)</h2>
<p>后缀表达式就是在某个表达式的后面加上 操作符。 严格的讲,每个主要表达式(primary expression)都是一个后缀表达式</p>
<p>Swift 标准库提供了下列后缀表达式:</p>
<ul>
<li>++ Increment</li>
<li>-- Decrement</li>
</ul>
<p>对于这些操作符的使用,请参见: Basic Operators and Advanced Operators</p>
<blockquote>
<p>后缀表达式的语法</p>
<p><em>postfix-expression</em><em>primary-expression</em>
<em>postfix-expression</em><em>postfix-expression</em>­<em>postfix-operator</em>
<em>postfix-expression</em><em>function-call-expression</em>­
<em>postfix-expression</em><em>initializer-expression</em>­
<em>postfix-expression</em><em>explicit-member-expression</em>­
<em>postfix-expression</em><em>postfix-self-expression</em>­
<em>postfix-expression</em><em>dynamic-type-expression</em>­
<em>postfix-expression</em><em>subscript-expression</em>­
<em>postfix-expression</em><em>forced-value-expression</em>­
<em>postfix-expression</em><em>optional-chaining-expression</em>­</p>
</blockquote>
<h3 id="-function-call-expression-">函数调用表达式( Function Call Expression)</h3>
<p>函数调用表达式由函数名和参数列表组成。它的形式如下:</p>
<p><code>function name</code>(<code>argument value 1</code>, <code>argument value 2</code>)</p>
<p>The function name can be any expression whose value is of a function type.
(不用翻译了, 太罗嗦)</p>
<p>如果该function 的声明中指定了参数的名字,那么在调用的时候也必须得写出来. 例如:</p>
<p><code>function name</code>(<code>argument name 1</code>: <code>argument value 1</code>, <code>argument name 2</code>: <code>argument value 2</code>)</p>
<p>可以在 函数调用表达式的尾部(最后一个参数之后)加上 一个闭包(closure) 该闭包会被目标函数理解并执行。它具有如下两种写法:</p>
<pre><code class="lang-swift">// someFunction takes an integer and a closure as its arguments
someFunction(x, {$0 == 13})
someFunction(x) {$0 == 13}
</code></pre>
<p>如果闭包是该函数的唯一参数,那么圆括号可以省略。</p>
<pre><code class="lang-swift">// someFunction takes a closure as its only argument
myData.someMethod() {$0 == 13}
myData.someMethod {$0 == 13}
</code></pre>
<blockquote>
<p>GRAMMAR OF A FUNCTION CALL EXPRESSION</p>
<p><em>function-call-expression</em><em>postfix-expression</em>­<em>parenthesized-expression</em>
<em>function-call-expression</em><em>postfix-expression</em>­<em>parenthesized-expression</em>­(opt)­<em>trailing-closure</em>­
<em>trailing-closure</em><em>closure-expression</em>­</p>
</blockquote>
<h3 id="-initializer-expression-">初始化函数表达式(Initializer Expression)</h3>
<p>Initializer表达式用来给某个Type初始化。 它的形式如下:</p>
<p><code>expression</code>.init(<code>initializer arguments</code>)</p>
<p>(Initializer表达式用来给某个Type初始化。) 跟函数(function)不同, initializer 不能返回值。</p>
<pre><code class="lang-swift">var x = SomeClass.someClassFunction // ok
var y = SomeClass.init // error
```swift
可以通过 initializer 表达式来委托调用(delegate to )到superclass的initializers.
```swift
class SomeSubClass: SomeSuperClass {
init() {
// subclass initialization goes here
super.init()
}
}
</code></pre>
<blockquote>
<p>initializer表达式的语法</p>
<p><em>initializer-expression</em><em>postfix-expression</em>­.­init­</p>
</blockquote>
<h3 id="-explicit-member-expression-">显式成员表达式(Explicit Member Expression)</h3>
<p>显示成员表达式允许我们访问type, tuple, module的成员变量。它的形式如下</p>
<p><code>expression</code>.<code>member name</code></p>
<p>该member 就是某个type在声明时候所定义(declaration or extension) 的变量, 例如:</p>
<pre><code class="lang-swift">class SomeClass {
var someProperty = 42
}
let c = SomeClass()
let y = c.someProperty // Member access
</code></pre>
<p>对于tuple, 要根据它们出现的顺序(0, 1, 2...)来使用:</p>
<pre><code class="lang-swift">var t = (10, 20, 30)
t.0 = t.1
// Now t is (20, 20, 30)
</code></pre>
<p>The members of a module access the top-level declarations of that module.
(不确定对于某个module的member的调用只能调用在top-level声明中的member.)</p>
<blockquote>
<p>显示成员表达式的语法</p>
<p><em>explicit-member-expression</em><em>postfix-expression</em>­.­<em>decimal-digit</em>­
<em>explicit-member-expression</em><em>postfix-expression</em>­.­<em>identifier</em>­<em>generic-argument-clause</em>(opt)</p>
</blockquote>
<h3 id="-self-postfix-self-expression-">后缀self表达式(Postfix Self Expression)</h3>
<p>后缀表达式由 某个表达式 + &#39;.self&#39; 组成. 形式如下:</p>
<p><code>expression</code>.self
<code>type</code>.self</p>
<p>形式1 表示会返回 expression 的值。例如: x.self 返回 x</p>
<p>形式2返回对应的type。我们可以用它来动态的获取某个instance的type。</p>
<blockquote>
<p>后缀self表达式的语法</p>
<p><em>postfix-self-expression</em><em>postfix-expression</em>­.­self­</p>
</blockquote>
<h3 id="dynamic-dynamic-type-expression-">dynamic表达式(Dynamic Type Expression)</h3>
<p>(因为dynamicType是一个独有的方法所以这里保留了英文单词未作翻译, --- 类似与self expression)</p>
<p>dynamicType 表达式由 某个表达式 + &#39;.dynamicType&#39; 组成。</p>
<p><code>expression</code>.dynamicType</p>
<p>上面的形式中, expression 不能是某type的名字(当然了,如果我都知道它的名字了还需要动态来获取它吗)。动态类型表达式会返回&quot;运行时&quot;某个instance的type, 具体请看下面的列子:</p>
<pre><code class="lang-swift">class SomeBaseClass {
class func printClassName() {
println(&quot;SomeBaseClass&quot;)
}
}
class SomeSubClass: SomeBaseClass {
override class func printClassName() {
println(&quot;SomeSubClass&quot;)
}
}
let someInstance: SomeBaseClass = SomeSubClass()
// someInstance is of type SomeBaseClass at compile time, but
// someInstance is of type SomeSubClass at runtime
someInstance.dynamicType.printClassName()
// prints &quot;SomeSubClass&quot;
</code></pre>
<blockquote>
<p>dynamic type 表达式</p>
<p><em>dynamic-type-expression</em><em>postfix-expression</em>­.­dynamicType­</p>
</blockquote>
<h3 id="-subscript-expression-">下标表达式( Subscript Expression)</h3>
<p>下标表达式提供了通过下标访问getter/setter 的方法。它的形式是:</p>
<p><code>expression</code>[<code>index expressions</code>]</p>
<p>可以通过下标表达式通过getter获取某个值或者通过setter赋予某个值.</p>
<p>关于subscript的声明请参见 Protocol Subscript Declaration.</p>
<blockquote>
<p>下标表达式的语法</p>
<p><em>subscript-expression</em><em>postfix-expression</em>­[­<em>expression-list</em>­]­</p>
</blockquote>
<h3 id="-forced-value-expression-">强制取值表达式(Forced-Value Expression)</h3>
<p>强制取值表达式用来获取某个目标表达式的值(该目标表达式的值必须不是nil )。它的形式如下:</p>
<p><code>expression</code>!</p>
<p>如果该表达式的值不是nil, 则返回对应的值。 否则,抛出运行时错误(runtime error)。</p>
<blockquote>
<p>强制取值表达式的语法</p>
<p><em>forced-value-expression</em><em>postfix-expression</em>­!­</p>
</blockquote>
<h3 id="-optional-chaining-expression-">可选链表达式(Optional-Chaining Expression)</h3>
<p>可选链表达式由目标表达式 + &#39;?&#39; 组成,形式如下:</p>
<p><code>expression</code>?</p>
<p>后缀&#39;?&#39; 返回目标表达式的值,把它做为可选的参数传递给后续的表达式</p>
<p>如果某个后缀表达式包含了可选链表达式,那么它的执行过程就比较特殊: 首先先判断该可选链表达式的值,如果是 nil, 整个后缀表达式都返回 nil, 如果该可选链的值不是nil, 则正常返回该后缀表达式的值(依次执行它的各个子表达式。在这两种情况下该后缀表达式仍然是一个optional type(In either case, the value of the postfix expression is still of an optional type)</p>
<p>如果某个&quot;后缀表达式&quot;&quot;子表达式&quot;中包含了&quot;可选链表达式&quot;那么只有最外层的表达式返回的才是一个optional type. 例如,在下面的例子中, 如果c 不是nil, 那么 c?.property.performAction() 这句代码在执行时就会先获得c 的property方法然后调用 performAction()方法。 然后对于 &quot;c?.property.performAction()&quot; 这个整体它的返回值是一个optional type.</p>
<pre><code class="lang-swift">var c: SomeClass?
var result: Bool? = c?.property.performAction()
</code></pre>
<p>如果不使用可选链表达式,那么 上面例子的代码跟下面例子等价:</p>
<pre><code class="lang-swift">if let unwrappedC = c {
result = unwrappedC.property.performAction()
}
</code></pre>
<blockquote>
<p>可选链表达式的语法</p>
<p><em>optional-chaining-expression</em><em>postfix-expression</em>­?­</p>
</blockquote>
</section>
</div>
</div>
</div>

View File

@ -46,7 +46,7 @@
<div class="book" data-level="3.6" data-basepath=".." data-revision="1402377857835">
<div class="book" data-level="3.6" data-basepath=".." data-revision="1402386668059">
<div class="book-header">
<!-- Actions Left -->
<a href="#" class="btn pull-left toggle-summary" aria-label="Toggle summary"><i class="fa fa-align-justify"></i></a>

View File

@ -46,7 +46,7 @@
<div class="book" data-level="3.7" data-basepath=".." data-revision="1402377857835">
<div class="book" data-level="3.7" data-basepath=".." data-revision="1402386668059">
<div class="book-header">
<!-- Actions Left -->
<a href="#" class="btn pull-left toggle-summary" aria-label="Toggle summary"><i class="fa fa-align-justify"></i></a>
@ -587,7 +587,7 @@
<div class="page-inner">
<section class="normal" id="section-gitbook_45">
<section class="normal" id="section-gitbook_432">
<h1 id="-">特性</h1>
<p>特性提供了关于声明和类型的更多信息。在Swift中有两类特性用于修饰声明的以及用于修饰类型的。例如<code>required</code>特性,当应用于一个类的指定或便利初始化器声明时,表明它的每个子类都必须实现那个初始化器。再比如<code>noreturn</code>特性,当应用于函数或方法类型时,表明该函数或方法不会返回到它的调用者。</p>

View File

@ -46,7 +46,7 @@
<div class="book" data-level="3.8" data-basepath=".." data-revision="1402377857835">
<div class="book" data-level="3.8" data-basepath=".." data-revision="1402386668059">
<div class="book-header">
<!-- Actions Left -->
<a href="#" class="btn pull-left toggle-summary" aria-label="Toggle summary"><i class="fa fa-align-justify"></i></a>
@ -587,7 +587,7 @@
<div class="page-inner">
<section class="normal" id="section-gitbook_52">
<section class="normal" id="section-gitbook_440">
<h1 id="-patterns-">模式Patterns</h1>
<p>模式pattern代表了单个值或者复合值的结构。例如元组<code>(1, 2)</code>的结构是逗号分隔的,包含两个元素的列表。因为模式代表一种值的结构,而不是特定的某个值,你可以把模式和各种同类型的值匹配起来。比如,<code>(x, y)</code>可以匹配元组<code>(1, 2)</code>,以及任何含两个元素的元组。除了将模式与一个值匹配外,你可以从合成值中提取出部分或全部,然后分别把各个部分和一个常量或变量绑定起来。</p>

View File

@ -46,7 +46,7 @@
<div class="book" data-level="3.9" data-basepath=".." data-revision="1402377857835">
<div class="book" data-level="3.9" data-basepath=".." data-revision="1402386668059">
<div class="book-header">
<!-- Actions Left -->
<a href="#" class="btn pull-left toggle-summary" aria-label="Toggle summary"><i class="fa fa-align-justify"></i></a>
@ -587,7 +587,7 @@
<div class="page-inner">
<section class="normal" id="section-gitbook_53">
<section class="normal" id="section-gitbook_441">
<h1 id="-">泛型参数</h1>
<hr>

View File

@ -44,7 +44,7 @@
<div class="book" data-level="3.10" data-basepath=".." data-revision="1402377857835">
<div class="book" data-level="3.10" data-basepath=".." data-revision="1402386668059">
<div class="book-header">
<!-- Actions Left -->
<a href="#" class="btn pull-left toggle-summary" aria-label="Toggle summary"><i class="fa fa-align-justify"></i></a>
@ -585,7 +585,7 @@
<div class="page-inner">
<section class="normal" id="section-gitbook_55">
<section class="normal" id="section-gitbook_443">
<h1 id="-">语法总结</h1>
<p>本页包含内容:</p>

View File

@ -46,7 +46,7 @@
<div class="book" data-level="3.5" data-basepath=".." data-revision="1402377857835">
<div class="book" data-level="3.5" data-basepath=".." data-revision="1402386668059">
<div class="book-header">
<!-- Actions Left -->
<a href="#" class="btn pull-left toggle-summary" aria-label="Toggle summary"><i class="fa fa-align-justify"></i></a>
@ -587,7 +587,7 @@
<div class="page-inner">
<section class="normal" id="section-gitbook_56">
<section class="normal" id="section-gitbook_444">
<h1 id="-">语句</h1>
<p>在 Swift 中有两种类型的语句简单语句和控制流语句。简单语句是最常见的用于构造表达式和声明。控制流语句则用于控制程序执行的流程Swift 中有三种类型的控制流语句:循环语句、分支语句和控制传递语句。</p>

View File

@ -46,7 +46,7 @@
<div class="book" data-level="3" data-basepath=".." data-revision="1402377857835">
<div class="book" data-level="3" data-basepath=".." data-revision="1402386668059">
<div class="book-header">
<!-- Actions Left -->
<a href="#" class="btn pull-left toggle-summary" aria-label="Toggle summary"><i class="fa fa-align-justify"></i></a>

View File

@ -44,7 +44,7 @@
<div class="book" data-level="0" data-basepath="." data-revision="1402377857835">
<div class="book" data-level="0" data-basepath="." data-revision="1402386668059">
<div class="book-header">
<!-- Actions Left -->
<a href="#" class="btn pull-left toggle-summary" aria-label="Toggle summary"><i class="fa fa-align-justify"></i></a>
@ -585,7 +585,7 @@
<div class="page-inner">
<section class="normal" id="section-gitbook_3">
<section class="normal" id="section-gitbook_385">
<h1 id="swift-">Swift 编程语言</h1>
<p>Swift 是苹果在 WWDC 2014 上发布的一款全新的编程语言,本书译自苹果官方的 Swift 教程《The Swift Programming Language》。</p>

View File

@ -1,5 +1,5 @@
CACHE MANIFEST
# Revision 1402377857836
# Revision 1402386668060
CACHE:
index.html
@ -23,11 +23,11 @@ chapter2/14_Initialization.html
chapter2/15_Deinitialization.html
chapter2/16_Automatic_Reference_Counting.html
chapter2/17_Optional_Chaining.html
chapter2/19_Nested_Types.html
chapter2/18_Type_Casting.html
chapter2/19_Nested_Types.html
chapter2/20_Extensions.html
chapter2/21_Protocols.html
chapter2/22_Generics.html
chapter2/21_Protocols.html
chapter2/23_Advanced_Operators.html
chapter2/chapter2.html
chapter3/06_Attributes.html
@ -77,8 +77,8 @@ gitbook/jsrepl/sandbox.html
gitbook/jsrepl/sandbox.js
gitbook/print.css
gitbook/style.css
gitbook/plugins/gitbook-plugin-mathjax/plugin.js
gitbook/plugins/gitbook-plugin-mixpanel/plugin.js
gitbook/plugins/gitbook-plugin-mathjax/plugin.js
NETWORK:
*

File diff suppressed because one or more lines are too long

View File

@ -78,7 +78,7 @@ Swift让所有数值类型都支持了基本的四则运算:
let dog: Character = "d"
let cow: Character = "c"
let dogCow = dog + cow
// 译者注: 原的引号内是很可爱的小狗和小牛, 但win os下不支持表情字符, 所以改成了普通字符
// 译者注: 原的引号内是很可爱的小狗和小牛, 但win os下不支持表情字符, 所以改成了普通字符
// dogCow 现在是 "dc"
```
详细请点击 [字符,字符串的拼接](http://#).
@ -91,7 +91,7 @@ let dogCow = dog + cow
> 求余运算(%)在其他语言也叫取模运算. 然而严格说来, 我们看该运算符对负数的操作结果, `求余` 比 `取模` 更合适些.
我们来谈谈取余是怎么回事, 计算 `9 % 4`, 你先计算出4的多少倍会刚好可以容入 `9` 中.
我们来谈谈取余是怎么回事, 计算 `9 % 4`, 你先计算出4的多少倍会刚好可以容入 `9` 中.
2倍, 非常好, 那余数是1 (用'*'标出)
@ -312,7 +312,7 @@ if hasHeader {
第一段代码例子使用了三目条件运算, 所以一行代码就能让我们得到正确答案. 这比第二段代码简洁得多, 无需将 `rowHeight` 定义成变量, 因为它的值无需在 `if` 语句中改变.
三目条件运算提供有效率且便捷的方式来表达二选一的选择. 需要注意的事, 过度使用三目条件运算就会由简洁的代码变成难懂的代码. 我们应避免在一个组合语句使用多个三目条件运算符.
三目条件运算提供有效率且便捷的方式来表达二选一的选择. 需要注意的事, 过度使用三目条件运算就会由简洁的代码变成难懂的代码. 我们应避免在一个组合语句使用多个三目条件运算符.
# 区间运算符
@ -334,7 +334,7 @@ for index in 1...5 {
// 5 * 5 = 25
```
关于 `for-in`, 请看 [控制流](Control Flow).
关于 `for-in`, 请看 [控制流](Control Flow).
## 半闭区间

View File

@ -1 +1,332 @@
# 集合类型 (Collection Types)
# 集合类型 (Collection Types)
Swift语言提供经典的数组和字典两种集合类型来存储集合数据。数组用来按顺序存储相同类型的数据。字典虽然无序存储相同类型数据值但是需要由独有的标识符引用和寻址就是键值对
Swift语言里的数组和字典中存储的数据值类型必须明确。 这意味着我们不能把不正确的数据类型插入其中。 同时这也说明我们完全可以对获取出的值类型非常自信。 Swift对显式类型集合的使用确保了我们的代码对工作所需要的类型非常清楚也让我们在开发中可以早早地找到任何的类型不匹配错误。
> 注意:
Swift的数组结构在被声明成常量和变量或者被传入函数与方法中时会相对于其他类型展现出不同的特性。 获取更多信息请参见see Mutability of Collections and Assignment and Copy Behavior for Collection Types。集合的可变性与集合在赋值和复制中的行为章节
## 数组
数组使用有序列表存储相同类型的多重数据。相同的值可以多次出现在一个数组的不同位置中。
Swift数组对存储数据有具体要求。 不同于 Objective-C的`NSArray``NSMutableArray`类,他们可以存储任何类型的实例而且不提供他们返回对象的任何本质信息。 在 Swift 中,数据值在被存储进入某个数组之前类型必须明确,方法是通过显式的类型标注或类型推断,而且不是必须是`class`类型。例如: 如果我们创建了一个`Int`值类型的数组,我们不能往其中插入任何不是`Int`类型的数据。 Swift 中的数组是类型安全的,并且它们中包含的类型必须明确。
### 数组的简单语法
写 Swift 数组应该遵循像`Array<SomeType>`这样的形式其中sometype是这个数组中唯一允许存在的数据类型。 我们也可以使用像`SomeType[]`这样的简单语法。 尽管两种形式在功能上是一样的, 但是我们推荐较短的那种,而且在本文中都会使用这种形式来使用数组。
### 数组构造语句
我们可以使用字面语句来进行数组构造,这是一种用一个或者多个数值构造数组的简单方法。字面语句是一系列由逗号分割并由方括号包含的数值。
`[value 1, value 2, value 3]`
下面这个例子创建了一个叫做`shoppingList`并且存储字符串的数组:
var shoppingList: String[] = ["Eggs", "Milk"]
// shoppingList 已经被构造并且拥有两个初始项。
`shoppingList`变量被声明为“字符串值类型的数组“,记作`String[]`。 因为这个数组被规定只有`String`一种数据结构,所以只有`String`类型可以在其中被存取。 在这里,`shoppinglist`数组由两个`String`值(`"Eggs"``"Milk"`)构造,并且由字面语句定义。
> 注意:
`Shoppinglist`数组被声明为变量(`var`关键字创建)而不是常量(`let`创建)是因为以后可能会有更多的数据项被插入其中。
在这个例子中,字面语句仅仅包含两个`String`值。匹配了该数组的变量声明(只能包含`String`的数组),所以这个字面语句的分配过程就是允许用两个初始项来构造`shoppinglist`
由 于Swift 的类型推断机制,当我们用字面语句构造只拥有相同类型值数组的时候,我们不必把数组的类型定义清楚。 `shoppinglist`的构造也可以这样写:
var shoppingList = ["Eggs", "Milk"]
因为所有字面语句中的值都是相同的类型Swift 可以推断出`String[]``shoppinglist`中变量的正确类型。
### 访问和修改数组
我们可以通过数组的方法和属性来访问和修改数组,或者下标语法。
还可以使用数组的只读属性`count`来获取数组中的数据项数量。
println("The shopping list contains \(shoppingList.count) items.")
// 打印出"The shopping list contains 2 items."这个数组有2个项
使用布尔项`isEmpty`来作为检查`count`属性的值是否为0的捷径。
if shoppingList.isEmpty {
println("The shopping list is empty.")
} else {
println("The shopping list is not empty.")
}
// 打印 "The shopping list is not empty."shoppinglist不是空的
也可以使用`append`方法在数组后面添加新的数据项:
shoppingList.append("Flour")
// shoppingList 现在有3个数据项有人在摊煎饼
除此之外,使用加法赋值运算符(`+=`)也可以直接在数组后面添加数据项:
shoppingList += "Baking Powder"
// shoppingList 现在有四项了
我们也可以使用加法赋值运算符(`+=`)直接添加拥有相同类型数据的数组。
shoppingList += ["Chocolate Spread", "Cheese", "Butter"]
// shoppingList 现在有7项了
可以直接使用下标语法来获取数组中的数据项,把我们需要的数据项的索引值放在直接放在数组名称的方括号中:
var firstItem = shoppingList[0]
// 第一项是 "Eggs"
注意第一项在数组中的索引值是`0`而不是`1`。 Swift 中的数组索引总是从零开始。
我们也可以用下标来改变某个已有索引值对应的数据值:
shoppingList[0] = "Six eggs"
// 其中的第一项现在是 "Six eggs" 而不是 "Eggs"
还可以利用下标来一次改变一系列数据值,即使新数据和原有数据的数量是不一样的。下面的例子把`"Chocolate Spread"``"Cheese"`,和`"Butter"`替换为`"Bananas"``"Apples"`
shoppingList[4...6] = ["Bananas", "Apples"]
// shoppingList 现在有六项
> 注意:
我们不能使用下标语法在数组尾部添加新项。如果我们试着用这种方法对索引越界的数据进行检索或者设置新值的操作,我们会引发一个运行期错误。我们可以使用索引值和数组的`count`属性进行比较来在使用某个索引之前先检验是否有效。除了当`count`等于0时说明这是个空数组最大索引值一直是`count - 1`,因为数组都是零起索引。
调用数组的`insert(atIndex:)`方法来在某个具体索引值之前添加数据项:
shoppingList.insert("Maple Syrup", atIndex: 0)
// shoppingList 现在有7项
// "Maple Syrup" 现在是这个列表中的第一项
这次`insert`函数调用把值为`"Maple Syrup"`的新数据项插入shopping列表的最开始位置并且使用`0`作为索引值。
类似的我们可以使用`removeAtIndex`方法来移除数组中的某一项。这个方法把数组在特定索引值中存储的数据项移除并且返回这个被移除的数据项(我们不需要的时候就可以无视它):
let mapleSyrup = shoppingList.removeAtIndex(0)
//索引值为0的数据项被移除
// shoppingList 现在只有6项而且不包括Maple Syrup
// mapleSyrup常量的值等于被移除数据项的值 "Maple Syrup"
数据项被移除后数组中的空出项会被自动填补,所以现在索引值为`0`的数据项的值再次等于`"Six eggs"`:
firstItem = shoppingList[0]
// firstItem 现在等于 "Six eggs"
如果我们只想把数组中的最后一项移除,可以使用`removeLast`方法而不是`removeAtIndex`方法来避免我们需要获取数组的`count`属性。就像后者一样,前者也会返回被移除的数据项:
let apples = shoppingList.removeLast()
// 数组的最后一项被移除了
// shoppingList现在只有5项不包括cheese
// apples 常量的值现在等于"Apples" 字符串
### 数组的遍历
我们可以使用`for-in`循环来遍历所有数组中的数据项:
for item in shoppingList {
println(item)
}
// Six eggs
// Milk
// Flour
// Baking Powder
// Bananas
如果我们同时需要每个数据项的值和索引值,可以使用全局`enumerate`函数来进行数组遍历。`enumerate`返回一个由每一个数据项索引值和数据值组成的键值对组。我们可以把这个键值对组分解成临时常量或者变量来进行遍历:
for (index, value) in enumerate(shoppingList) {
println("Item \(index + 1): \(value)")
}
// Item 1: Six eggs
// Item 2: Milk
// Item 3: Flour
// Item 4: Baking Powder
// Item 5: Bananas
更多关于`for-in`循环的介绍请参见[for循环](待添加链接)。
### 创建并且构造一个数组
我们可以使用构造语法来创建一个由特定数据类型构成的空数组:
var someInts = Int[]()
println("someInts is of type Int[] with \(someInts。count) items。")
// 打印 "someInts is of type Int[] with 0 items。"someInts是0数据项的Int[]数组)
注意`someInts`被设置为一个`Int[]`构造函数的输出所以它的变量类型被定义为`Int[]`
除此之外,如果代码上下文中提供了类型信息, 例如一个函数参数或者一个已经定义好类型的常量或者变量,我们可以使用空数组语句创建一个空数组,它的写法很简单:`[]`(一对空方括号):
someInts.append(3)
// someInts 现在包含一个INT值
someInts = []
// someInts 现在是空数组但是仍然是Int[]类型的。
Swift 中的`Array`类型还提供一个可以创建特定大小并且所有数据都被默认的构造方法。我们可以把准备加入新数组的数据项数量(`count`)和适当类型的初始值(`repeatedValue`)传入数组构造函数:
var threeDoubles = Double[](count: 3, repeatedValue:0.0)
// threeDoubles 是一种 Double[]数组, 等于 [0.0, 0.0, 0.0]
因为类型推断的存在,我们使用这种构造方法的时候不需要特别指定数组中存储的数据类型,因为类型可以从默认值推断出来:
var anotherThreeDoubles = Array(count: 3, repeatedValue: 2.5)
// anotherThreeDoubles is inferred as Double[], and equals [2.5, 2.5, 2.5]
最后,我们可以使用加法操作符(`+`)来组合两种已存在的相同类型数组。新数组的数据类型会被从两个数组的数据类型中推断出来:
var sixDoubles = threeDoubles + anotherThreeDoubles
// sixDoubles 被推断为 Double[], 等于 [0.0, 0.0, 0.0, 2.5, 2.5, 2.5]
## 字典
字典是一种存储相同类型多重数据的存储器。每个值value都关联独特的键key键作为字典中的这个值数据的标识符。和数组中的数据项不同字典中的数据项并没有具体顺序。我们在需要通过标识符访问数据的时候使用字典这种方法很大程度上和我们在现实世界中使用字典查字义的方法一样。
Swift 的字典使用时需要具体规定可以存储键和值类型。不同于 Objective-C 的`NSDictionary``NSMutableDictionary` 类可以使用任何类型的对象来作键和值并且不提供任何关于这些对象的本质信息。在 Swift 中,在某个特定字典中可以存储的键和值必须提前定义清楚,方法是通过显性类型标注或者类型推断。
Swift 的字典使用`Dictionary<KeyType, ValueType>`定义,其中`KeyType`是字典中键的数据类型,`ValueType`是字典中对应于这些键所存储值的数据类型。
`KeyType`的唯一限制就是可哈希的,这样可以保证它是独一无二的,所有的 Swift 基本类型(例如`String``Int` `Double``Bool`)都是默认可哈希的,并且所有这些类型都可以在字典中当做键使用。未关联值的枚举成员(参见[枚举](链接待添加))也是默认可哈希的。
## 字典字面语句
我们可以使用字典字面语句来构造字典,他们和我们刚才介绍过的数组字面语句拥有相似语法。一个字典字面语句是一个定义拥有一个或者多个键值对的字典集合的简单语句。
一个键值对是一个`key`和一个`value`的结合体。在字典字面语句中,每一个键值对的键和值都由冒号分割。这些键值对构成一个列表,其中这些键值对由方括号包含并且由逗号分割:
[key 1: value 1, key 2: value 2, key 3: value 3]
下面的例子创建了一个存储国际机场名称的字典。在这个字典中键是三个字母的国际航空运输相关代码,值是机场名称:
var airports: Dictionary<String, String> = ["TYO": "Tokyo", "DUB": "Dublin"]
`airports`字典被定义为一种`Dictionary<String, String>`,它意味着这个字典的键和值都是`String`类型。
> 注意:
`airports`字典被声明为变量(用`var`关键字)而不是常量(`let`关键字)因为后来更多的机场信息会被添加到这个示例字典中。
`airports`字典使用字典字面语句初始化,包含两个键值对。第一对的键是`TYO`,值是`Tokyo`。第二对的键是`DUB`,值是`Dublin`
这个字典语句包含了两个`String: String`类型的键值对。他们对应`airports`变量声明的类型(一个只有`String`键和`String`值的字典)所以这个字典字面语句是构造两个初始数据项的`airport`字典。
和数组一样,如果我们使用字面语句构造字典就不用把类型定义清楚。`airports`的也可以用这种方法简短定义:
var airports = ["TYO": "Tokyo", "DUB": "Dublin"]
因为这个语句中所有的键和值都分别是相同的数据类型Swift 可以推断出`Dictionary<String, String>``airports`字典的正确类型。
### 读取和修改字典
我们可以通过字典的方法和属性来读取和修改字典,或者使用下标语法。和数组一样,我们可以通过字典的只读属性`count`来获取某个字典的数据项数量:
println("The dictionary of airports contains \(airports.count) items.")
// 打印 "The dictionary of airports contains 2 items."(这个字典有两个数据项)
我们也可以在字典中使用下标语法来添加新的数据项。可以使用一个合适类型的key作为下标索引并且分配新的合适类型的值
airports["LHR"] = "London"
// airports 字典现在有三个数据项
我们也可以使用下标语法来改变特定键对应的值:
airports["LHR"] = "London Heathrow"
// "LHR"对应的值 被改为 "London Heathrow
作为另一种下标方法,字典的`updateValue(forKey:)`方法可以设置或者更新特定键对应的值。就像上面所示的示例,`updateValue(forKey:)`方法在这个键不存在对应值的时候设置值或者在存在时更新已存在的值。和上面的下标方法不一样,这个方法返回更新值之前的原值。这样方便我们检查更新是否成功。
`updateValue(forKey:)`函数会返回包含一个字典值类型的可选值。举例来说:对于存储`String`值的字典,这个函数会返回一个`String?`或者“可选 `String`”类型的值。如果值存在,则这个可选值值等于被替换的值,否则将会是`nil`
if let oldValue = airports.updateValue("Dublin Internation", forKey: "DUB") {
println("The old value for DUB was \(oldValue).")
}
// 打印出 "The old value for DUB was Dublin."dub原值是dublin
我们也可以使用下标语法来在字典中检索特定键对应的值。由于使用一个没有值的键这种情况是有可能发生的,可选 类型返回这个键存在的相关值,否则就返回`nil`
if let airportName = airports["DUB"] {
println("The name of the airport is \(airportName).")
} else {
println("That airport is not in the airports dictionary.")
}
// 打印 "The name of the airport is Dublin INTernation."(机场的名字是都柏林国际)
我们还可以使用下标语法来通过给某个键的对应值赋值为`nil`来从字典里移除一个键值对:
airports["APL"] = "Apple Internation"
// "Apple Internation"不是真的 APL机场, 删除它
airports["APL"] = nil
// APL现在被移除了
另外,`removeValueForKey`方法也可以用来在字典中移除键值对。这个方法在键值对存在的情况下会移除该键值对并且返回被移除的value或者在没有值的情况下返回`nil`
if let removedValue = airports.removeValueForKey("DUB") {
println("The removed airport's name is \(removedValue).")
} else {
println("The airports dictionary does not contain a value for DUB.")
}
// 打印 "The removed airport's name is Dublin International."(被移除的机场名字是都柏林国际)
### 字典遍历
我们可以使用`for-in`循环来遍历某个字典中的键值对。每一个字典中的数据项都由`(key, value)`元组形式返回,并且我们可以使用暂时性常量或者变量来分解这些元组:
for (airportCode, airportName) in airports {
prINTln("\(airportCode): \(airportName)")
}
// TYO: Tokyo
// LHR: London Heathrow
`for-in`循环请参见[For 循环](链接待添加)。
我们也可以通过访问他的`keys`或者`values`属性(都是可遍历集合)检索一个字典的键或者值:
for airportCode in airports.keys {
prINTln("Airport code: \(airportCode)")
}
// Airport code: TYO
// Airport code: LHR
for airportName in airports。values {
prINTln("Airport name: \(airportName)")
}
// Airport name: Tokyo
// Airport name: London Heathrow
如果我们只是需要使用某个字典的键集合或者值集合来作为某个接受`Array`实例 API 的参数,可以直接使用`keys`或者`values`属性直接构造一个新数组:
let airportCodes = Array(airports.keys)
// airportCodes is ["TYO", "LHR"]
let airportNames = Array(airports.values)
// airportNames is ["Tokyo", "London Heathrow"]
> 注意:
Swift 的字典类型是无序集合类型。其中字典键,值,键值对在遍历的时候会重新排列,而且其中顺序是不固定的。
### 创建一个空字典
我们可以像数组一样使用构造语法创建一个空字典:
var namesOfIntegers = Dictionary<Int, String>()
// namesOfIntegers 是一个空的 Dictionary<Int, String>
这个例子创建了一个`Int, String`类型的空字典来储存英语对整数的命名。他的键是`Int`型,值是`String`型。
如果上下文已经提供了信息类型,我们可以使用空字典字面语句来创建一个空字典,记作`[:]`(中括号中放一个冒号):
namesOfIntegers[16] = "sixteen"
// namesOfIntegers 现在包含一个键值对
namesOfIntegers = [:]
// namesOfIntegers 又成为了一个 Int, String类型的空字典
> 注意:
在后台Swift 的数组和字典都是由泛型集合来实现的,想了解更多泛型和集合信息请参见[泛型](链接待添加)。
## 集合的可变性
数组和字典都是在单个集合中存储可变值。如果我们创建一个数组或者字典并且把它分配成一个变量,这个集合将会是可变的。这意味着我们可以在创建之后添加更多或移除已存在的数据项来改变这个集合的大小。与此相反,如果我们把数组或字典分配成常量,那么他就是不可变的,它的大小不能被改变。
对字典来说,不可变性也意味着我们不能替换其中任何现有键所对应的值。不可变字典的内容在被首次设定之后不能更改。
不可变行对数组来说有一点不同,当然我们不能试着改变任何不可变数组的大小,但是我们可以重新设定相对现存索引所对应的值。这使得 Swift 数组在大小被固定的时候依然可以做的很棒。
Swift 数组的可变性行为同时影响了数组实例如何被分配和修改,想获取更多信息,请参见[Assignment and Copy Behavior for Collection Types](待翻译,链接待添加,请查看对应章节的翻译)。
> 注意:
在我们不需要改变数组大小的时候创建不可变数组是很好的习惯。如此 Swift 编译器可以优化我们创建的集合。

View File

@ -11,20 +11,20 @@
protocol SomeProtocol {
// 协议内容
}
`类`,`结构体`,`枚举`的名称后加上`协议名称`,中间以冒号`:`分隔即可实现协议;实现多个协议时,各协议之间用逗号`,`分隔,如下所示:
struct SomeStructure: FirstProtocol, AnotherProtocol {
// 结构体内容
}
当某个类含有`父类`的同时并实现了协议,应当把`父类`放在所有的`协议`之前,如下所示:
class SomeClass: SomeSuperClass, FirstProtocol, AnotherProtocol {
// 类的内容
}
## 属性要求
`协议`能够要求其`遵循者`必须含有一些**特定名称和类型**的`实例属性(instance property)``类属性 (type property)`,也能够要求属性的`(设置权限)settable``(访问权限)gettable`,但它不要求`属性``存储型属性(stored property)`还是`计算型属性(calculate property)`.
@ -35,17 +35,17 @@
var musBeSettable : Int { get set }
var doesNotNeedToBeSettable: Int { get }
}
`类`来实现`协议`时,使用`class`关键字来表示该属性为类成员;用`结构体``枚举`实现`协议`时,则使用`static`关键字来表示:
protocol AnotherProtocol {
class var someTypeProperty: Int { get set }
}
protocol FullyNamed {
var fullName: String { get }
}
}
`FullyNamed`协议含有`fullName`属性.因此其`遵循者`必须含有一个名为`fullName`,类型为`String`的可读属性.
struct Person: FullyNamed{
@ -53,11 +53,11 @@
}
let john = Person(fullName: "John Appleseed")
//john.fullName 为 "John Appleseed"
`Person`结构体含有一个名为`fullName``存储型属性`,完整的`遵循`了协议.(*若协议未被完整遵循,编译时则会报错*).
`Person`结构体含有一个名为`fullName``存储型属性`,完整的`遵循`了协议.(*若协议未被完整遵循,编译时则会报错*).
如下所示,`Startship``遵循``FullyNamed`协议:
class Starship: FullyNamed {
var prefix: String?
var name: String
@ -71,7 +71,7 @@
}
var ncc1701 = Starship(name: "Enterprise", prefix: "USS")
// ncc1701.fullName == "USS Enterprise"
`Starship`类将`fullName`实现为可读的`计算型属性`.它的每一个实例都有一个名为`name`的必备属性和一个名为`prefix`的可选属性. 当`prefix`存在时,将`prefix`插入到`name`之前来为`Starship`构建`fullName`
## 方法要求
@ -85,11 +85,11 @@
protocol SomeProtocol {
class func someTypeMethod()
}
protocol RandomNumberGenerator {
func random() -> Double
}
`RandomNumberGenerator`协议要求其`遵循者`必须拥有一个名为`random`, 返回值类型为`Double`的实例方法. (我们假设随机数在[0,1]区间内).
`LinearCongruentialGenerator``遵循``RandomNumberGenerator`协议,并提供了一个叫做*线性同余生成器(linear congruential generator)*的伪随机数算法.
@ -109,7 +109,7 @@
// 输出 : "Here's a random number: 0.37464991998171"
println("And another one: \(generator.random())")
// 输出 : "And another one: 0.729023776863283"
## 突变方法要求
能在`方法``函数`内部改变实例类型的方法称为`突变方法`.在`值类型(Value Type)`(*译者注:特指结构体和枚举*)中的的`函数`前缀加上`mutating`关键字来表示该函数允许改变该实例和其属性的类型. 这一变换过程在[Modifyting Value Types from Within Instance Methods](1)章节中有详细描述.
@ -123,7 +123,7 @@
protocol Togglable {
mutating func toggle()
}
当使用`枚举``结构体`来实现`Togglabl`协议时,必须在`toggle`方法前加上`mutating`关键字.
如下所示,`OnOffSwitch`枚举`遵循``Togglable`协议,`On`,`Off`两个成员用于表示当前状态
@ -148,7 +148,7 @@
`协议`本身不实现任何功能,但你可以将它当做`类型`来使用.
使用场景:
使用场景:
* 作为函数,方法或构造器中的参数类型,返回值类型
* 作为常量,变量,属性的类型
@ -159,7 +159,7 @@
class Dice {
let sides: Int
let generator: RandomNumberGenerator
init(sides: Int, generator: RandomNumberGenerator) {
init(sides: Int, generator: RandomNumberGenerator) {
self.sides = sides
self.generator = generator
}
@ -188,7 +188,7 @@
//Random dice roll is 4
//Random dice roll is 5
//Random dice roll is 4
## 委托(代理)模式
委托是一种设计模式(*译者注: 想起了那年 UITableViewDelegate 中的奔跑,那是我逝去的Objective-C...*),它允许`类``结构体`将一些需要它们负责的功能`交由(委托)`给其他的类型.
@ -197,7 +197,7 @@
委托模式可以用来响应特定的动作或接收外部数据源提供的数据,而无需要知道外部数据源的类型.
下文是两个基于骰子游戏的协议:
下文是两个基于骰子游戏的协议:
protocol DiceGame {
var dice: Dice { get }
@ -208,9 +208,9 @@
func game(game: DiceGame, didStartNewTurnWithDiceRoll diceRoll:Int)
func gameDidEnd(game: DiceGame)
}
`DiceGame`协议可以在任意含有骰子的游戏中实现,`DiceGameDelegate`协议可以用来追踪`DiceGame`的游戏过程
如下所示,`SnakesAndLadders``Snakes and Ladders`(译者注:[Control Flow](2)章节有该游戏的详细介绍)游戏的新版本.新版本使用`Dice`作为骰子,并且实现了`DiceGame``DiceGameDelegate`协议
class SnakesAndLadders: DiceGame {
@ -235,7 +235,7 @@
break gameLoop
case let newSquare where newSquare > finalSquare:
continue gameLoop
default:
default:
square += diceRoll
square += board[square]
}
@ -243,7 +243,7 @@
delegate?.gameDIdEnd(self)
}
}
游戏的`初始化设置(setup)`被为`SnakesAndLadders`类的`构造器(initializer)`实现.所有的游戏逻辑被转移到了`play`方法中.
> 注意:因为`delegate`并不是该游戏的必备条件,`delegate`被定义为遵循`DiceGameDelegate`协议的可选属性
@ -301,7 +301,7 @@
protocol TextRepresentable {
func asText() -> String
}
通过`扩展`为上一节中提到的`Dice`类遵循`TextRepresentable`协议
extension Dice: TextRepresentable {
@ -309,7 +309,7 @@
return "A \(sides)-sided dice"
}
}
从现在起,`Dice`类型的实例可被当作`TextRepresentable`类型:
let d12 = Dice(sides: 12,generator: LinearCongruentialGenerator())
@ -334,7 +334,7 @@
var name: String
func asText() -> String {
return "A hamster named \(name)"
}
}
}
extension Hamster: TextRepresentabl {}
@ -375,7 +375,7 @@
如下所示,`PrettyTextRepresentable`协议继承了`TextRepresentable`协议
protocol PrettyTextRepresentable: TextRepresentable {
func asPrettyText() -> String
func asPrettyText() -> String
}
`遵循``PrettyTextRepresentable`协议的同时,也需要`遵循`TextRepresentable`协议.
@ -444,9 +444,9 @@
使用`is`检验协议一致性,使用`as`将协议类型`向下转换(downcast)`为的其他协议类型.检验与转换的语法和之前相同(*详情查看[Typy Casting章节](5)*):
* `is`操作符用来检查实例是否`遵循`了某个`协议`.
* `is`操作符用来检查实例是否`遵循`了某个`协议`.
* `as?`返回一个可选值,当实例`遵循`协议时,返回该协议类型;否则返回`nil`
* `as`用以强制向下转型.
* `as`用以强制向下转型.
@objc protocol HasArea {
var area: Double { get }
@ -538,7 +538,7 @@
`count`属性用于存储当前的值,`increment`方法用来为`count`赋值.
`increment`方法通过`可选链`,尝试从两种`可选成员`中获取`count`.
1. 由于`dataSource`可能为`nil`,因此在`dataSource`后边加上了`?`标记来表明只在`dataSource`非空时才去调用incrementForCount`方法.
2. 即使`dataSource`存在,但是也无法保证其是否实现了`incrementForCount`方法,因此在`incrementForCount`方法后边也加有`?`标记