make gitbook
This commit is contained in:
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="1.1" data-basepath=".." data-revision="1402750255397">
|
||||
<div class="book" data-level="1.1" data-basepath=".." data-revision="1402759431779">
|
||||
<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_506">
|
||||
|
||||
<blockquote>
|
||||
<p>翻译:numbbbbb<br>校对:yeahdongcn</p>
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="1.2" data-basepath=".." data-revision="1402750255397">
|
||||
<div class="book" data-level="1.2" data-basepath=".." data-revision="1402759431779">
|
||||
<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_508">
|
||||
|
||||
<blockquote>
|
||||
<p>翻译:numbbbbb<br>校对:shinyzhu, stanzhai</p>
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="1" data-basepath=".." data-revision="1402750255397">
|
||||
<div class="book" data-level="1" data-basepath=".." data-revision="1402759431779">
|
||||
<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_510">
|
||||
|
||||
<h1 id="-swift">欢迎使用 Swift</h1>
|
||||
<p>在本章中您将了解 Swift 的特性和开发历史,并对 Swift 有一个初步的了解。</p>
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="2.1" data-basepath=".." data-revision="1402750255397">
|
||||
<div class="book" data-level="2.1" data-basepath=".." data-revision="1402759431779">
|
||||
<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_513">
|
||||
|
||||
<blockquote>
|
||||
<p>翻译:numbbbbb, lyuka, JaySurplus<br>校对:lslxdx </p>
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="2.2" data-basepath=".." data-revision="1402750255397">
|
||||
<div class="book" data-level="2.2" data-basepath=".." data-revision="1402759431779">
|
||||
<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_55">
|
||||
<section class="normal" id="section-gitbook_534">
|
||||
|
||||
<blockquote>
|
||||
<p>翻译:xielingwang<br>校对:Evilcome </p>
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="2.3" data-basepath=".." data-revision="1402750255397">
|
||||
<div class="book" data-level="2.3" data-basepath=".." data-revision="1402759431779">
|
||||
<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_515">
|
||||
|
||||
<blockquote>
|
||||
<p>翻译:wh1100717<br>校对:Hawstein </p>
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="2.4" data-basepath=".." data-revision="1402750255397">
|
||||
<div class="book" data-level="2.4" data-basepath=".." data-revision="1402759431779">
|
||||
<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_41">
|
||||
<section class="normal" id="section-gitbook_517">
|
||||
|
||||
<blockquote>
|
||||
<p>翻译:zqp
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="2.5" data-basepath=".." data-revision="1402750255397">
|
||||
<div class="book" data-level="2.5" data-basepath=".." data-revision="1402759431779">
|
||||
<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_43">
|
||||
<section class="normal" id="section-gitbook_519">
|
||||
|
||||
<blockquote>
|
||||
<p>翻译:vclwei, coverxit, NicePiao<br>校对:coverxit, stanzhai</p>
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="2.6" data-basepath=".." data-revision="1402750255397">
|
||||
<div class="book" data-level="2.6" data-basepath=".." data-revision="1402759431779">
|
||||
<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_521">
|
||||
|
||||
<blockquote>
|
||||
<p>翻译:honghaoz<br>校对:LunaticM </p>
|
||||
@ -603,7 +603,7 @@
|
||||
<li><a href="#Nested_Functions">函数嵌套(Nested Functions)</a></li>
|
||||
</ul>
|
||||
<p>函数是用来完成特定任务的独立的代码块。你给一个函数起一个合适的名字,用来标示函数做什么,并且当函数需要执行的时候,这个名字会被“调用”。</p>
|
||||
<p>Swift 统一的函数语法足够灵活,可以用来表示任何函数,包括从最简单的没有参数名字的 C 风格函数,到复杂的带局部和外部参数名的 Objective-C 风格函数。参数可以提供默认值,以简化函数调用。参数也可以即当做传入参数,也当做传出参数,也就是说,一旦函数执行结束,传入的参数值可以被修改。</p>
|
||||
<p>Swift 统一的函数语法足够灵活,可以用来表示任何函数,包括从最简单的没有参数名字的 C 风格函数,到复杂的带局部和外部参数名的 Objective-C 风格函数。参数可以提供默认值,以简化函数调用。参数也可以既当做传入参数,也当做传出参数,也就是说,一旦函数执行结束,传入的参数值可以被修改。</p>
|
||||
<p>在 Swift 中,每个函数都有一种类型,包括函数的参数值类型和返回值类型。你可以把函数类型当做任何其他普通变量类型一样处理,这样就可以更简单地把函数当做别的函数的参数,也可以从其他函数中返回函数。函数的定义可以写在在其他函数定义中,这样可以在嵌套函数范围内实现功能封装。</p>
|
||||
<p><a name="Defining_and_Calling_Functions"></a></p>
|
||||
<h2 id="-defining-and-calling-functions-">函数的定义与调用(Defining and Calling Functions)</h2>
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="2.7" data-basepath=".." data-revision="1402750255397">
|
||||
<div class="book" data-level="2.7" data-basepath=".." data-revision="1402759431779">
|
||||
<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_523">
|
||||
|
||||
<blockquote>
|
||||
<p>翻译:wh1100717<br>校对:lyuka </p>
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="2.8" data-basepath=".." data-revision="1402750255397">
|
||||
<div class="book" data-level="2.8" data-basepath=".." data-revision="1402759431779">
|
||||
<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_49">
|
||||
<section class="normal" id="section-gitbook_525">
|
||||
|
||||
<blockquote>
|
||||
<p>翻译:yankuangshi<br>校对:shinyzhu </p>
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="2.9" data-basepath=".." data-revision="1402750255397">
|
||||
<div class="book" data-level="2.9" data-basepath=".." data-revision="1402759431779">
|
||||
<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_59">
|
||||
<section class="normal" id="section-gitbook_527">
|
||||
|
||||
<blockquote>
|
||||
<p>翻译:JaySurplus<br>校对:sg552 </p>
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="2.10" data-basepath=".." data-revision="1402750255397">
|
||||
<div class="book" data-level="2.10" data-basepath=".." data-revision="1402759431779">
|
||||
<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_57">
|
||||
<section class="normal" id="section-gitbook_528">
|
||||
|
||||
<blockquote>
|
||||
<p>翻译:shinyzhu<br>校对:pp-prog </p>
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="2.11" data-basepath=".." data-revision="1402750255397">
|
||||
<div class="book" data-level="2.11" data-basepath=".." data-revision="1402759431779">
|
||||
<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_530">
|
||||
|
||||
<blockquote>
|
||||
<p>翻译:pp-prog<br>校对:zqp </p>
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="2.12" data-basepath=".." data-revision="1402750255397">
|
||||
<div class="book" data-level="2.12" data-basepath=".." data-revision="1402759431779">
|
||||
<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_532">
|
||||
|
||||
<blockquote>
|
||||
<p>翻译:siemenliu<br>校对:zq54zquan </p>
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="2.13" data-basepath=".." data-revision="1402750255397">
|
||||
<div class="book" data-level="2.13" data-basepath=".." data-revision="1402759431779">
|
||||
<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_511">
|
||||
|
||||
<blockquote>
|
||||
<p>翻译:Hawstein<br>校对:menlongsheng </p>
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="2.14" data-basepath=".." data-revision="1402750255397">
|
||||
<div class="book" data-level="2.14" data-basepath=".." data-revision="1402759431779">
|
||||
<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_60">
|
||||
<section class="normal" id="section-gitbook_536">
|
||||
|
||||
<blockquote>
|
||||
<p>翻译:lifedim<br>校对:lifedim </p>
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="2.15" data-basepath=".." data-revision="1402750255397">
|
||||
<div class="book" data-level="2.15" data-basepath=".." data-revision="1402759431779">
|
||||
<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_62">
|
||||
<section class="normal" id="section-gitbook_538">
|
||||
|
||||
<blockquote>
|
||||
<p>翻译:bruce0505<br>校对:fd5788 </p>
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="2.16" data-basepath=".." data-revision="1402750255397">
|
||||
<div class="book" data-level="2.16" data-basepath=".." data-revision="1402759431779">
|
||||
<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,11 +587,10 @@
|
||||
|
||||
<div class="page-inner">
|
||||
|
||||
<section class="normal" id="section-gitbook_64">
|
||||
<section class="normal" id="section-gitbook_540">
|
||||
|
||||
<blockquote>
|
||||
<p>翻译:TimothyYe</p>
|
||||
<p>校对:Hawstein</p>
|
||||
<p>翻译:TimothyYe<br>校对:Hawstein </p>
|
||||
</blockquote>
|
||||
<h1 id="-">自动引用计数</h1>
|
||||
<hr>
|
||||
@ -607,8 +606,7 @@
|
||||
<p>Swift 使用自动引用计数(ARC)这一机制来跟踪和管理你的应用程序的内存。通常情况下,Swift 的内存管理机制会一直起着作用,你无须自己来考虑内存的管理。ARC 会在类的实例不再被使用时,自动释放其占用的内存。</p>
|
||||
<p>然而,在少数情况下,ARC 为了能帮助你管理内存,需要更多的关于你的代码之间关系的信息。本章描述了这些情况,并且为你示范怎样启用 ARC 来管理你的应用程序的内存。</p>
|
||||
<blockquote>
|
||||
<p>注意:</p>
|
||||
<p>引用计数仅仅应用于类的实例。结构体和枚举类型是值类型,不是引用类型,也不是通过引用的方式存储和传递。</p>
|
||||
<p>注意:<br>引用计数仅仅应用于类的实例。结构体和枚举类型是值类型,不是引用类型,也不是通过引用的方式存储和传递。</p>
|
||||
</blockquote>
|
||||
<p><a name="how_arc_works"></a></p>
|
||||
<h2 id="-">自动引用计数的工作机制</h2>
|
||||
@ -619,77 +617,86 @@
|
||||
<p><a name="arc_in_action"></a></p>
|
||||
<h2 id="-">自动引用计数实践</h2>
|
||||
<p>下面的例子展示了自动引用计数的工作机制。例子以一个简单的<code>Person</code>类开始,并定义了一个叫<code>name</code>的常量属性:</p>
|
||||
<pre><code> class Person {
|
||||
<pre><code class="lang-swift">class Person {
|
||||
let name: String
|
||||
|
||||
init(name: String) {
|
||||
self.name = name
|
||||
println("\(name) is being initialized")
|
||||
}
|
||||
|
||||
deinit {
|
||||
println("\(name) is being deinitialized")
|
||||
}
|
||||
}
|
||||
</code></pre><p><code>Person</code>类有一个构造函数,此构造函数为实例的<code>name</code>属性赋值并打印出信息,以表明初始化过程生效。<code>Person</code>类同时也拥有析构函数,同样会在实例被销毁的时候打印出信息。</p>
|
||||
}
|
||||
</code></pre>
|
||||
<p><code>Person</code>类有一个构造函数,此构造函数为实例的<code>name</code>属性赋值并打印出信息,以表明初始化过程生效。<code>Person</code>类同时也拥有析构函数,同样会在实例被销毁的时候打印出信息。</p>
|
||||
<p>接下来的代码片段定义了三个类型为<code>Person?</code>的变量,用来按照代码片段中的顺序,为新的<code>Person</code>实例建立多个引用。由于这些变量是被定义为可选类型(Person?,而不是Person),它们的值会被自动初始化为<code>nil</code>,目前还不会引用到<code>Person</code>类的实例。</p>
|
||||
<pre><code> var reference1: Person?
|
||||
var reference2: Person?
|
||||
var reference3: Person?
|
||||
</code></pre><p>现在你可以创建<code>Person</code>类的新实例,并且将它赋值给三个变量其中的一个:</p>
|
||||
<pre><code> reference1 = Person(name: "John Appleseed")
|
||||
// prints "John Appleseed is being initialized”
|
||||
</code></pre><p>应当注意到当你调用<code>Person</code>类的构造函数的时候,"John Appleseed is being initialized”会被打印出来。由此可以确定构造函数被执行。</p>
|
||||
<pre><code class="lang-swift">var reference1: Person?
|
||||
var reference2: Person?
|
||||
var reference3: Person?
|
||||
</code></pre>
|
||||
<p>现在你可以创建<code>Person</code>类的新实例,并且将它赋值给三个变量其中的一个:</p>
|
||||
<pre><code class="lang-swift">reference1 = Person(name: "John Appleseed")
|
||||
// prints "John Appleseed is being initialized”
|
||||
</code></pre>
|
||||
<p>应当注意到当你调用<code>Person</code>类的构造函数的时候,"John Appleseed is being initialized”会被打印出来。由此可以确定构造函数被执行。</p>
|
||||
<p>由于<code>Person</code>类的新实例被赋值给了<code>reference1</code>变量,所以<code>reference1</code>到<code>Person</code>类的新实例之间建立了一个强引用。正是因为这个强引用,ARC 会保证<code>Person</code>实例被保持在内存中不被销毁。</p>
|
||||
<p>如果你将同样的<code>Person</code>实例也赋值给其他两个变量,该实例又会多出两个强引用:</p>
|
||||
<pre><code> reference2 = reference1
|
||||
reference3 = reference1
|
||||
</code></pre><p>现在这个<code>Person</code>实例已经有三个强引用了。</p>
|
||||
<pre><code class="lang-swift">reference2 = reference1
|
||||
reference3 = reference1
|
||||
</code></pre>
|
||||
<p>现在这个<code>Person</code>实例已经有三个强引用了。</p>
|
||||
<p>如果你通过给两个变量赋值<code>nil</code>的方式断开两个强引用()包括最先的那个强引用),只留下一个强引用,<code>Person</code>实例不会被销毁:</p>
|
||||
<pre><code>reference2 = nil
|
||||
<pre><code class="lang-swift">reference2 = nil
|
||||
reference3 = nil
|
||||
</code></pre><p>ARC 会在第三个,也即最后一个强引用被断开的时候,销毁<code>Person</code>实例,这也意味着你不再使用这个<code>Person</code>实例:</p>
|
||||
<pre><code>reference3 = nil
|
||||
</code></pre>
|
||||
<p>ARC 会在第三个,也即最后一个强引用被断开的时候,销毁<code>Person</code>实例,这也意味着你不再使用这个<code>Person</code>实例:</p>
|
||||
<pre><code class="lang-swift">reference3 = nil
|
||||
// prints "John Appleseed is being deinitialized"
|
||||
</code></pre><p><a name="strong_reference_cycles_between_class_instances"></a></p>
|
||||
</code></pre>
|
||||
<p><a name="strong_reference_cycles_between_class_instances"></a></p>
|
||||
<h2 id="-">类实例之间的循环强引用</h2>
|
||||
<p>在上面的例子中,ARC 会跟踪你所新创建的<code>Person</code>实例的引用数量,并且会在<code>Person</code>实例不再被需要时销毁它。</p>
|
||||
<p>然而,我们可能会写出这样的代码,一个类永远不会有0个强引用。这种情况发生在两个类实例互相保持对方的强引用,并让对方不被销毁。这就是所谓的循环强引用。</p>
|
||||
<p>你可以通过定义类之间的关系为弱引用或者无主引用,以此替代强引用,从而解决循环强引用的问题。具体的过程在<a href="#resolving_strong_reference_cycles_between_class_instances">解决类实例之间的循环强引用</a>中有描述。不管怎样,在你学习怎样解决循环强引用之前,很有必要了解一下它是怎样产生的。</p>
|
||||
<p>下面展示了一个不经意产生循环强引用的例子。例子定义了两个类:<code>Person</code>和<code>Apartment</code>,用来建模公寓和它其中的居民:</p>
|
||||
<pre><code>class Person {
|
||||
<pre><code class="lang-swift">class Person {
|
||||
let name: String
|
||||
init(name: String) { self.name = name }
|
||||
var apartment: Apartment?
|
||||
deinit { println("\(name) is being deinitialized") }
|
||||
}
|
||||
|
||||
class Apartment {
|
||||
</code></pre>
|
||||
<pre><code class="lang-swift">class Apartment {
|
||||
let number: Int
|
||||
init(number: Int) { self.number = number }
|
||||
var tenant: Person?
|
||||
deinit { println("Apartment #\(number) is being deinitialized") }
|
||||
}
|
||||
</code></pre><p>每一个<code>Person</code>实例有一个类型为<code>String</code>,名字为<code>name</code>的属性,并有一个可选的初始化为<code>nil</code>的<code>apartment</code>属性。<code>apartment</code>属性是可选的,因为一个人并不总是拥有公寓。</p>
|
||||
</code></pre>
|
||||
<p>每一个<code>Person</code>实例有一个类型为<code>String</code>,名字为<code>name</code>的属性,并有一个可选的初始化为<code>nil</code>的<code>apartment</code>属性。<code>apartment</code>属性是可选的,因为一个人并不总是拥有公寓。</p>
|
||||
<p>类似的,每个<code>Apartment</code>实例有一个叫<code>number</code>,类型为<code>Int</code>的属性,并有一个可选的初始化为<code>nil</code>的<code>tenant</code>属性。<code>tenant</code>属性是可选的,因为一栋公寓并不总是有居民。</p>
|
||||
<p>这两个类都定义了析构函数,用以在类实例被析构的时候输出信息。这让你能够知晓<code>Person</code>和<code>Apartment</code>的实例是否像预期的那样被销毁。</p>
|
||||
<p>接下来的代码片段定义了两个可选类型的变量<code>john</code>和<code>number73</code>,并分别被设定为下面的<code>Apartment</code>和<code>Person</code>的实例。这两个变量都被初始化为<code>nil</code>,并为可选的:</p>
|
||||
<pre><code>var john: Person?
|
||||
<pre><code class="lang-swift">var john: Person?
|
||||
var number73: Apartment?
|
||||
</code></pre><p>现在你可以创建特定的<code>Person</code>和<code>Apartment</code>实例并将类实例赋值给<code>john</code>和<code>number73</code>变量:</p>
|
||||
<pre><code>john = Person(name: "John Appleseed")
|
||||
</code></pre>
|
||||
<p>现在你可以创建特定的<code>Person</code>和<code>Apartment</code>实例并将类实例赋值给<code>john</code>和<code>number73</code>变量:</p>
|
||||
<pre><code class="lang-swift">john = Person(name: "John Appleseed")
|
||||
number73 = Apartment(number: 73)
|
||||
</code></pre><p>在两个实例被创建和赋值后,下图表现了强引用的关系。变量<code>john</code>现在有一个指向<code>Person</code>实例的强引用,而变量<code>number73</code>有一个指向<code>Apartment</code>实例的强引用:</p>
|
||||
</code></pre>
|
||||
<p>在两个实例被创建和赋值后,下图表现了强引用的关系。变量<code>john</code>现在有一个指向<code>Person</code>实例的强引用,而变量<code>number73</code>有一个指向<code>Apartment</code>实例的强引用:</p>
|
||||
<p><img src="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/referenceCycle01_2x.png" alt=""></p>
|
||||
<p>现在你能够将这两个实例关联在一起,这样人就能有公寓住了,而公寓也有了房客。注意感叹号是用来展开和访问可选变量<code>john</code>和<code>number73</code>中的实例,这样实例的属性才能被赋值:</p>
|
||||
<pre><code>john!.apartment = number73
|
||||
<pre><code class="lang-swift">john!.apartment = number73
|
||||
number73!.tenant = john
|
||||
</code></pre><p>在将两个实例联系在一起之后,强引用的关系如图所示:</p>
|
||||
</code></pre>
|
||||
<p>在将两个实例联系在一起之后,强引用的关系如图所示:</p>
|
||||
<p><img src="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/referenceCycle02_2x.png" alt=""></p>
|
||||
<p>不幸的是,将这两个实例关联在一起之后,一个循环强引用被创建了。<code>Person</code>实例现在有了一个指向<code>Apartment</code>实例的强引用,而<code>Apartment</code>实例也有了一个指向<code>Person</code>实例的强引用。因此,当你断开<code>john</code>和<code>number73</code>变量所持有的强引用时,引用计数并不会降为 0,实例也不会被 ARC 销毁:</p>
|
||||
<pre><code>john = nil
|
||||
<pre><code class="lang-swift">john = nil
|
||||
number73 = nil
|
||||
</code></pre><p>注意,当你把这两个变量设为<code>nil</code>时,没有任何一个析构函数被调用。强引用循环阻止了<code>Person</code>和<code>Apartment</code>类实例的销毁,并在你的应用程序中造成了内存泄漏。</p>
|
||||
</code></pre>
|
||||
<p>注意,当你把这两个变量设为<code>nil</code>时,没有任何一个析构函数被调用。强引用循环阻止了<code>Person</code>和<code>Apartment</code>类实例的销毁,并在你的应用程序中造成了内存泄漏。</p>
|
||||
<p>在你将<code>john</code>和<code>number73</code>赋值为<code>nil</code>后,强引用关系如下图:</p>
|
||||
<p><img src="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/referenceCycle03_2x.png" alt=""></p>
|
||||
<p><code>Person</code>和<code>Apartment</code>实例之间的强引用关系保留了下来并且不会被断开。</p>
|
||||
@ -702,27 +709,27 @@ number73 = nil
|
||||
<p>弱引用不会牢牢保持住引用的实例,并且不会阻止 ARC 销毁被引用的实例。这种行为阻止了引用变为循环强引用。声明属性或者变量时,在前面加上<code>weak</code>关键字表明这是一个弱引用。</p>
|
||||
<p>在实例的生命周期中,如果某些时候引用没有值,那么弱引用可以阻止循环强引用。如果引用总是有值,则可以使用无主引用,在<a href="#2">无主引用</a>中有描述。在上面<code>Apartment</code>的例子中,一个公寓的生命周期中,有时是没有“居民”的,因此适合使用弱引用来解决循环强引用。</p>
|
||||
<blockquote>
|
||||
<p>注意:
|
||||
弱引用必须被声明为变量,表明其值能在运行时被修改。弱引用不能被声明为常量。</p>
|
||||
<p>注意:<br>弱引用必须被声明为变量,表明其值能在运行时被修改。弱引用不能被声明为常量。 </p>
|
||||
</blockquote>
|
||||
<p>因为弱引用可以没有值,你必须将每一个弱引用声明为可选类型。可选类型是在 Swift 语言中推荐的用来表示可能没有值的类型。</p>
|
||||
<p>因为弱引用不会保持所引用的实例,即使引用存在,实例也有可能被销毁。因此,ARC 会在引用的实例被销毁后自动将其赋值为<code>nil</code>。你可以像其他可选值一样,检查弱引用的值是否存在,你永远也不会遇到被销毁了而不存在的实例。</p>
|
||||
<p>下面的例子跟上面<code>Person</code>和<code>Apartment</code>的例子一致,但是有一个重要的区别。这一次,<code>Apartment</code>的<code>tenant</code>属性被声明为弱引用:</p>
|
||||
<pre><code>class Person {
|
||||
<pre><code class="lang-swift">class Person {
|
||||
let name: String
|
||||
init(name: String) { self.name = name }
|
||||
var apartment: Apartment?
|
||||
deinit { println("\(name) is being deinitialized") }
|
||||
}
|
||||
|
||||
class Apartment {
|
||||
</code></pre>
|
||||
<pre><code class="lang-swift">class Apartment {
|
||||
let number: Int
|
||||
init(number: Int) { self.number = number }
|
||||
weak var tenant: Person?
|
||||
deinit { println("Apartment #\(number) is being deinitialized") }
|
||||
}
|
||||
</code></pre><p>然后跟之前一样,建立两个变量(john和number73)之间的强引用,并关联两个实例:</p>
|
||||
<pre><code>var john: Person?
|
||||
</code></pre>
|
||||
<p>然后跟之前一样,建立两个变量(john和number73)之间的强引用,并关联两个实例:</p>
|
||||
<pre><code class="lang-swift">var john: Person?
|
||||
var number73: Apartment?
|
||||
|
||||
john = Person(name: "John Appleseed")
|
||||
@ -730,33 +737,34 @@ number73 = Apartment(number: 73)
|
||||
|
||||
john!.apartment = number73
|
||||
number73!.tenant = john
|
||||
</code></pre><p>现在,两个关联在一起的实例的引用关系如下图所示:</p>
|
||||
</code></pre>
|
||||
<p>现在,两个关联在一起的实例的引用关系如下图所示:</p>
|
||||
<p><img src="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/weakReference01_2x.png" alt=""></p>
|
||||
<p><code>Person</code>实例依然保持对<code>Apartment</code>实例的强引用,但是<code>Apartment</code>实例只是对<code>Person</code>实例的弱引用。这意味着当你断开<code>john</code>变量所保持的强引用时,再也没有指向<code>Person</code>实例的强引用了:</p>
|
||||
<p><img src="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/weakReference02_2x.png" alt=""></p>
|
||||
<p>由于再也没有指向<code>Person</code>实例的强引用,该实例会被销毁:</p>
|
||||
<pre><code>john = nil
|
||||
<pre><code class="lang-swift">john = nil
|
||||
// prints "John Appleseed is being deinitialized"
|
||||
</code></pre><p>唯一剩下的指向<code>Apartment</code>实例的强引用来自于变量<code>number73</code>。如果你断开这个强引用,再也没有指向<code>Apartment</code>实例的强引用了:</p>
|
||||
</code></pre>
|
||||
<p>唯一剩下的指向<code>Apartment</code>实例的强引用来自于变量<code>number73</code>。如果你断开这个强引用,再也没有指向<code>Apartment</code>实例的强引用了:</p>
|
||||
<p><img src="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/weakReference03_2x.png" alt=""></p>
|
||||
<p>由于再也没有指向<code>Apartment</code>实例的强引用,该实例也会被销毁:</p>
|
||||
<pre><code>number73 = nil
|
||||
<pre><code class="lang-swift">number73 = nil
|
||||
// prints "Apartment #73 is being deinitialized"
|
||||
</code></pre><p>上面的两段代码展示了变量<code>john</code>和<code>number73</code>在被赋值为<code>nil</code>后,<code>Person</code>实例和<code>Apartment</code>实例的析构函数都打印出“销毁”的信息。这证明了引用循环被打破了。</p>
|
||||
</code></pre>
|
||||
<p>上面的两段代码展示了变量<code>john</code>和<code>number73</code>在被赋值为<code>nil</code>后,<code>Person</code>实例和<code>Apartment</code>实例的析构函数都打印出“销毁”的信息。这证明了引用循环被打破了。</p>
|
||||
<p><a name="2"></a></p>
|
||||
<h3 id="-">无主引用</h3>
|
||||
<p>和弱引用类似,无主引用不会牢牢保持住引用的实例。和弱引用不同的是,无主引用是永远有值的。因此,无主引用总是被定义为非可选类型(non-optional type)。你可以在声明属性或者变量时,在前面加上关键字<code>unowned</code>表示这是一个无主引用。</p>
|
||||
<p>由于无主引用是非可选类型,你不需要在使用它的时候将它展开。无主引用总是可以被直接访问。不过 ARC 无法在实例被销毁后将无主引用设为<code>nil</code>,因为非可选类型的变量不允许被赋值为<code>nil</code>。</p>
|
||||
<blockquote>
|
||||
<p>注意:
|
||||
如果你试图在实例被销毁后,访问该实例的无主引用,会触发运行时错误。使用无主引用,你必须确保引用始终指向一个未销毁的实例。</p>
|
||||
<p>还需要注意的是如果你试图访问实例已经被销毁的无主引用,程序会直接崩溃,而不会发生无法预期的行为。所以你应当避免这样的事情发生。</p>
|
||||
<p>注意:<br>如果你试图在实例被销毁后,访问该实例的无主引用,会触发运行时错误。使用无主引用,你必须确保引用始终指向一个未销毁的实例。<br>还需要注意的是如果你试图访问实例已经被销毁的无主引用,程序会直接崩溃,而不会发生无法预期的行为。所以你应当避免这样的事情发生。 </p>
|
||||
</blockquote>
|
||||
<p>下面的例子定义了两个类,<code>Customer</code>和<code>CreditCard</code>,模拟了银行客户和客户的信用卡。这两个类中,每一个都将另外一个类的实例作为自身的属性。这种关系会潜在的创造循环强引用。</p>
|
||||
<p><code>Customer</code>和<code>CreditCard</code>之间的关系与前面弱引用例子中<code>Apartment</code>和<code>Person</code>的关系截然不同。在这个数据模型中,一个客户可能有或者没有信用卡,但是一张信用卡总是关联着一个客户。为了表示这种关系,<code>Customer</code>类有一个可选类型的<code>card</code>属性,但是<code>CreditCard</code>类有一个非可选类型的<code>customer</code>属性。</p>
|
||||
<p>此外,只能通过将一个<code>number</code>值和<code>customer</code>实例传递给<code>CreditCard</code>构造函数的方式来创建<code>CreditCard</code>实例。这样可以确保当创建<code>CreditCard</code>实例时总是有一个<code>customer</code>实例与之关联。</p>
|
||||
<p>由于信用卡总是关联着一个客户,因此将<code>customer</code>属性定义为无主引用,用以避免循环强引用:</p>
|
||||
<pre><code>class Customer {
|
||||
<pre><code class="lang-swift">class Customer {
|
||||
let name: String
|
||||
var card: CreditCard?
|
||||
init(name: String) {
|
||||
@ -764,8 +772,8 @@ number73!.tenant = john
|
||||
}
|
||||
deinit { println("\(name) is being deinitialized") }
|
||||
}
|
||||
|
||||
class CreditCard {
|
||||
</code></pre>
|
||||
<pre><code class="lang-swift">class CreditCard {
|
||||
let number: Int
|
||||
unowned let customer: Customer
|
||||
init(number: Int, customer: Customer) {
|
||||
@ -774,21 +782,25 @@ class CreditCard {
|
||||
}
|
||||
deinit { println("Card #\(number) is being deinitialized") }
|
||||
}
|
||||
</code></pre><p>下面的代码片段定义了一个叫<code>john</code>的可选类型<code>Customer</code>变量,用来保存某个特定客户的引用。由于是可选类型,所以变量被初始化为<code>nil</code>。</p>
|
||||
<pre><code>var john: Customer?
|
||||
</code></pre><p>现在你可以创建<code>Customer</code>类的实例,用它初始化<code>CreditCard</code>实例,并将新创建的<code>CreditCard</code>实例赋值为客户的<code>card</code>属性。</p>
|
||||
<pre><code>john = Customer(name: "John Appleseed")
|
||||
</code></pre>
|
||||
<p>下面的代码片段定义了一个叫<code>john</code>的可选类型<code>Customer</code>变量,用来保存某个特定客户的引用。由于是可选类型,所以变量被初始化为<code>nil</code>。</p>
|
||||
<pre><code class="lang-swift">var john: Customer?
|
||||
</code></pre>
|
||||
<p>现在你可以创建<code>Customer</code>类的实例,用它初始化<code>CreditCard</code>实例,并将新创建的<code>CreditCard</code>实例赋值为客户的<code>card</code>属性。</p>
|
||||
<pre><code class="lang-swift">john = Customer(name: "John Appleseed")
|
||||
john!.card = CreditCard(number: 1234_5678_9012_3456, customer: john!)
|
||||
</code></pre><p>在你关联两个实例后,它们的引用关系如下图所示:</p>
|
||||
</code></pre>
|
||||
<p>在你关联两个实例后,它们的引用关系如下图所示:</p>
|
||||
<p><img src="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/unownedReference01_2x.png" alt=""></p>
|
||||
<p><code>Customer</code>实例持有对<code>CreditCard</code>实例的强引用,而<code>CreditCard</code>实例持有对<code>Customer</code>实例的无主引用。</p>
|
||||
<p>由于<code>customer</code>的无主引用,当你断开<code>john</code>变量持有的强引用时,再也没有指向<code>Customer</code>实例的强引用了:</p>
|
||||
<p><img src="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/unownedReference02_2x.png" alt=""></p>
|
||||
<p>由于再也没有指向<code>Customer</code>实例的强引用,该实例被销毁了。其后,再也没有指向<code>CreditCard</code>实例的强引用,该实例也随之被销毁了:</p>
|
||||
<pre><code>john = nil
|
||||
<pre><code class="lang-swift">john = nil
|
||||
// prints "John Appleseed is being deinitialized"
|
||||
// prints "Card #1234567890123456 is being deinitialized"
|
||||
</code></pre><p>最后的代码展示了在<code>john</code>变量被设为<code>nil</code>后<code>Customer</code>实例和<code>CreditCard</code>实例的构造函数都打印出了“销毁”的信息。</p>
|
||||
</code></pre>
|
||||
<p>最后的代码展示了在<code>john</code>变量被设为<code>nil</code>后<code>Customer</code>实例和<code>CreditCard</code>实例的构造函数都打印出了“销毁”的信息。</p>
|
||||
<h3 id="-">无主引用以及隐式解析可选属性</h3>
|
||||
<p>上面弱引用和无主引用的例子涵盖了两种常用的需要打破循环强引用的场景。</p>
|
||||
<p><code>Person</code>和<code>Apartment</code>的例子展示了两个属性的值都允许为<code>nil</code>,并会潜在的产生循环强引用。这种场景最适合用弱引用来解决。</p>
|
||||
@ -796,7 +808,7 @@ john!.card = CreditCard(number: 1234_5678_9012_3456, customer: john!)
|
||||
<p>然而,存在着第三种场景,在这种场景中,两个属性都必须有值,并且初始化完成后不能为<code>nil</code>。在这种场景中,需要一个类使用无主属性,而另外一个类使用隐式解析可选属性。</p>
|
||||
<p>这使两个属性在初始化完成后能被直接访问(不需要可选展开),同时避免了循环引用。这一节将为你展示如何建立这种关系。</p>
|
||||
<p>下面的例子定义了两个类,<code>Country</code>和<code>City</code>,每个类将另外一个类的实例保存为属性。在这个模型中,每个国家必须有首都,而每一个城市必须属于一个国家。为了实现这种关系,<code>Country</code>类拥有一个<code>capitalCity</code>属性,而<code>City</code>类有一个<code>country</code>属性:</p>
|
||||
<pre><code>class Country {
|
||||
<pre><code class="lang-swift">class Country {
|
||||
let name: String
|
||||
let capitalCity: City!
|
||||
init(name: String, capitalName: String) {
|
||||
@ -804,8 +816,8 @@ john!.card = CreditCard(number: 1234_5678_9012_3456, customer: john!)
|
||||
self.capitalCity = City(name: capitalName, country: self)
|
||||
}
|
||||
}
|
||||
|
||||
class City {
|
||||
</code></pre>
|
||||
<pre><code class="lang-swift">class City {
|
||||
let name: String
|
||||
unowned let country: Country
|
||||
init(name: String, country: Country) {
|
||||
@ -813,15 +825,17 @@ class City {
|
||||
self.country = country
|
||||
}
|
||||
}
|
||||
</code></pre><p>为了建立两个类的依赖关系,<code>City</code>的构造函数有一个<code>Country</code>实例的参数,并且将实例保存为<code>country</code>属性。</p>
|
||||
</code></pre>
|
||||
<p>为了建立两个类的依赖关系,<code>City</code>的构造函数有一个<code>Country</code>实例的参数,并且将实例保存为<code>country</code>属性。</p>
|
||||
<p><code>Country</code>的构造函数调用了<code>City</code>的构造函数。然而,只有<code>Country</code>的实例完全初始化完后,<code>Country</code>的构造函数才能把<code>self</code>传给<code>City</code>的构造函数。(<a href="14_Initialization.html">在两段式构造过程中有具体描述</a>)</p>
|
||||
<p>为了满足这种需求,通过在类型结尾处加上感叹号(City!)的方式,将<code>Country</code>的<code>capitalCity</code>属性声明为隐式解析可选类型的属性。这表示像其他可选类型一样,<code>capitalCity</code>属性的默认值为<code>nil</code>,但是不需要展开它的值就能访问它。(<a href="01_The_Basics.html">在隐式解析可选类型中有描述</a>)</p>
|
||||
<p>由于<code>capitalCity</code>默认值为<code>nil</code>,一旦<code>Country</code>的实例在构造函数中给<code>name</code>属性赋值后,整个初始化过程就完成了。这代表一旦<code>name</code>属性被赋值后,<code>Country</code>的构造函数就能引用并传递隐式的<code>self</code>。<code>Country</code>的构造函数在赋值<code>capitalCity</code>时,就能将<code>self</code>作为参数传递给<code>City</code>的构造函数。</p>
|
||||
<p>以上的意义在于你可以通过一条语句同时创建<code>Country</code>和<code>City</code>的实例,而不产生循环强引用,并且<code>capitalCity</code>的属性能被直接访问,而不需要通过感叹号来展开它的可选值:</p>
|
||||
<pre><code>var country = Country(name: "Canada", capitalName: "Ottawa")
|
||||
<pre><code class="lang-swift">var country = Country(name: "Canada", capitalName: "Ottawa")
|
||||
println("\(country.name)'s capital city is called \(country.capitalCity.name)")
|
||||
// prints "Canada's capital city is called Ottawa"
|
||||
</code></pre><p>在上面的例子中,使用隐式解析可选值的意义在于满足了两个类构造函数的需求。<code>capitalCity</code>属性在初始化完成后,能像非可选值一样使用和存取同时还避免了循环强引用。</p>
|
||||
</code></pre>
|
||||
<p>在上面的例子中,使用隐式解析可选值的意义在于满足了两个类构造函数的需求。<code>capitalCity</code>属性在初始化完成后,能像非可选值一样使用和存取同时还避免了循环强引用。</p>
|
||||
<p><a name="strong_reference_cycles_for_closures"></a></p>
|
||||
<h2 id="-">闭包引起的循环强引用</h2>
|
||||
<p>前面我们看到了循环强引用环是在两个类实例属性互相保持对方的强引用时产生的,还知道了如何用弱引用和无主引用来打破循环强引用。</p>
|
||||
@ -829,7 +843,7 @@ println("\(country.name)'s capital city is called \(country.capitalCity
|
||||
<p>循环强引用的产生,是因为闭包和类相似,都是引用类型。当你把一个闭包赋值给某个属性时,你也把一个引用赋值给了这个闭包。实质上,这跟之前的问题是一样的-两个强引用让彼此一直有效。但是,和两个类实例不同,这次一个是类实例,另一个是闭包。</p>
|
||||
<p>Swift 提供了一种优雅的方法来解决这个问题,称之为闭包占用列表(closuer capture list)。同样的,在学习如何用闭包占用列表破坏循环强引用之前,先来了解一下循环强引用是如何产生的,这对我们是很有帮助的。</p>
|
||||
<p>下面的例子为你展示了当一个闭包引用了<code>self</code>后是如何产生一个循环强引用的。例子中定义了一个叫<code>HTMLElement</code>的类,用一种简单的模型表示 HTML 中的一个单独的元素:</p>
|
||||
<pre><code>class HTMLElement {
|
||||
<pre><code class="lang-swift">class HTMLElement {
|
||||
|
||||
let name: String
|
||||
let text: String?
|
||||
@ -852,61 +866,61 @@ println("\(country.name)'s capital city is called \(country.capitalCity
|
||||
}
|
||||
|
||||
}
|
||||
</code></pre><p><code>HTMLElement</code>类定义了一个<code>name</code>属性来表示这个元素的名称,例如代表段落的"p",或者代表换行的"br"。<code>HTMLElement</code>还定义了一个可选属性<code>text</code>,用来设置和展现 HTML 元素的文本。</p>
|
||||
</code></pre>
|
||||
<p><code>HTMLElement</code>类定义了一个<code>name</code>属性来表示这个元素的名称,例如代表段落的"p",或者代表换行的"br"。<code>HTMLElement</code>还定义了一个可选属性<code>text</code>,用来设置和展现 HTML 元素的文本。</p>
|
||||
<p>除了上面的两个属性,<code>HTMLElement</code>还定义了一个<code>lazy</code>属性<code>asHTML</code>。这个属性引用了一个闭包,将<code>name</code>和<code>text</code>组合成 HTML 字符串片段。该属性是<code>() -> String</code>类型,或者可以理解为“一个没有参数,返回<code>String</code>的函数”。</p>
|
||||
<p>默认情况下,闭包赋值给了<code>asHTML</code>属性,这个闭包返回一个代表 HTML 标签的字符串。如果<code>text</code>值存在,该标签就包含可选值<code>text</code>;如果<code>text</code>不存在,该标签就不包含文本。对于段落元素,根据<code>text</code>是"some text"还是<code>nil</code>,闭包会返回"<code><p>some text</p></code>"或者"<code><p /></code>"。</p>
|
||||
<p>可以像实例方法那样去命名、使用<code>asHTML</code>属性。然而,由于<code>asHTML</code>是闭包而不是实例方法,如果你想改变特定元素的 HTML 处理的话,可以用自定义的闭包来取代默认值。</p>
|
||||
<blockquote>
|
||||
<p>注意:</p>
|
||||
<p><code>asHTML</code>声明为<code>lazy</code>属性,因为只有当元素确实需要处理为HTML输出的字符串时,才需要使用<code>asHTML</code>。也就是说,在默认的闭包中可以使用<code>self</code>,因为只有当初始化完成以及<code>self</code>确实存在后,才能访问<code>lazy</code>属性。</p>
|
||||
<p>注意:<br><code>asHTML</code>声明为<code>lazy</code>属性,因为只有当元素确实需要处理为HTML输出的字符串时,才需要使用<code>asHTML</code>。也就是说,在默认的闭包中可以使用<code>self</code>,因为只有当初始化完成以及<code>self</code>确实存在后,才能访问<code>lazy</code>属性。</p>
|
||||
</blockquote>
|
||||
<p><code>HTMLElement</code>类只提供一个构造函数,通过<code>name</code>和<code>text</code>(如果有的话)参数来初始化一个元素。该类也定义了一个析构函数,当<code>HTMLElement</code>实例被销毁时,打印一条消息。</p>
|
||||
<p>下面的代码展示了如何用<code>HTMLElement</code>类创建实例并打印消息。</p>
|
||||
<pre><code>var paragraph: HTMLElement? = HTMLElement(name: "p", text: "hello, world")
|
||||
<pre><code class="lang-swift">var paragraph: HTMLElement? = HTMLElement(name: "p", text: "hello, world")
|
||||
println(paragraph!.asHTML())
|
||||
// prints"hello, world"
|
||||
</code></pre><blockquote>
|
||||
<p>注意:</p>
|
||||
<p>上面的<code>paragraph</code>变量定义为<code>可选HTMLElement</code>,因此我们可以赋值<code>nil</code>给它来演示循环强引用。</p>
|
||||
</code></pre>
|
||||
<blockquote>
|
||||
<p>注意:<br>上面的<code>paragraph</code>变量定义为<code>可选HTMLElement</code>,因此我们可以赋值<code>nil</code>给它来演示循环强引用。</p>
|
||||
</blockquote>
|
||||
<p>不幸的是,上面写的<code>HTMLElement</code>类产生了类实例和<code>asHTML</code>默认值的闭包之间的循环强引用。循环强引用如下图所示:</p>
|
||||
<p><img src="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/closureReferenceCycle01_2x.png" alt=""></p>
|
||||
<p>实例的<code>asHTML</code>属性持有闭包的强引用。但是,闭包在其闭包体内使用了<code>self</code>(引用了<code>self.name</code>和<code>self.text</code>),因此闭包捕获了<code>self</code>,这意味着闭包又反过来持有了<code>HTMLElement</code>实例的强引用。这样两个对象就产生了循环强引用。(更多关于闭包捕获值的信息,请参考<a href="07_Closures.html">值捕获</a>)。</p>
|
||||
<blockquote>
|
||||
<p>注意:</p>
|
||||
<p>虽然闭包多次使用了<code>self</code>,它只捕获<code>HTMLElement</code>实例的一个强引用。</p>
|
||||
<p>注意:<br>虽然闭包多次使用了<code>self</code>,它只捕获<code>HTMLElement</code>实例的一个强引用。</p>
|
||||
</blockquote>
|
||||
<p>如果设置<code>paragraph</code>变量为<code>nil</code>,打破它持有的<code>HTMLElement</code>实例的强引用,<code>HTMLElement</code>实例和它的闭包都不会被销毁,也是因为循环强引用:</p>
|
||||
<pre><code>paragraph = nil
|
||||
</code></pre><p>注意<code>HTMLElementdeinitializer</code>中的消息并没有别打印,证明了<code>HTMLElement</code>实例并没有被销毁。</p>
|
||||
<pre><code class="lang-swift">paragraph = nil
|
||||
</code></pre>
|
||||
<p>注意<code>HTMLElementdeinitializer</code>中的消息并没有别打印,证明了<code>HTMLElement</code>实例并没有被销毁。</p>
|
||||
<p><a name="resolving_strong_reference_cycles_for_closures"></a></p>
|
||||
<h2 id="-">解决闭包引起的循环强引用</h2>
|
||||
<p>在定义闭包时同时定义捕获列表作为闭包的一部分,通过这种方式可以解决闭包和类实例之间的循环强引用。捕获列表定义了闭包体内捕获一个或者多个引用类型的规则。跟解决两个类实例间的循环强引用一样,声明每个捕获的引用为弱引用或无主引用,而不是强引用。应当根据代码关系来决定使用弱引用还是无主引用。</p>
|
||||
<blockquote>
|
||||
<p>注意:</p>
|
||||
<p>Swift 有如下要求:只要在闭包内使用<code>self</code>的成员,就要用<code>self.someProperty</code>或者<code>self.someMethod</code>(而不只是<code>someProperty</code>或<code>someMethod</code>)。这提醒你可能会不小心就捕获了<code>self</code>。</p>
|
||||
<p>注意:<br>Swift 有如下要求:只要在闭包内使用<code>self</code>的成员,就要用<code>self.someProperty</code>或者<code>self.someMethod</code>(而不只是<code>someProperty</code>或<code>someMethod</code>)。这提醒你可能会不小心就捕获了<code>self</code>。</p>
|
||||
</blockquote>
|
||||
<h3 id="-">定义捕获列表</h3>
|
||||
<p>捕获列表中的每个元素都是由<code>weak</code>或者<code>unowned</code>关键字和实例的引用(如<code>self</code>或<code>someInstance</code>)成对组成。每一对都在方括号中,通过逗号分开。</p>
|
||||
<p>捕获列表放置在闭包参数列表和返回类型之前:</p>
|
||||
<pre><code>@lazy var someClosure: (Int, String) -> String = {
|
||||
<pre><code class="lang-swift">@lazy var someClosure: (Int, String) -> String = {
|
||||
[unowned self] (index: Int, stringToProcess: String) -> String in
|
||||
// closure body goes here
|
||||
}
|
||||
</code></pre><p>如果闭包没有指定参数列表或者返回类型,则可以通过上下文推断,那么可以捕获列表放在闭包开始的地方,跟着是关键字<code>in</code>:</p>
|
||||
<pre><code>@lazy var someClosure: () -> String = {
|
||||
</code></pre>
|
||||
<p>如果闭包没有指定参数列表或者返回类型,则可以通过上下文推断,那么可以捕获列表放在闭包开始的地方,跟着是关键字<code>in</code>:</p>
|
||||
<pre><code class="lang-swift">@lazy var someClosure: () -> String = {
|
||||
[unowned self] in
|
||||
// closure body goes here
|
||||
}
|
||||
</code></pre><h3 id="-">弱引用和无主引用</h3>
|
||||
</code></pre>
|
||||
<h3 id="-">弱引用和无主引用</h3>
|
||||
<p>当闭包和捕获的实例总是互相引用时并且总是同时销毁时,将闭包内的捕获定义为无主引用。</p>
|
||||
<p>相反的,当捕获引用有时可能会是<code>nil</code>时,将闭包内的捕获定义为弱引用。弱引用总是可选类型,并且当引用的实例被销毁后,弱引用的值会自动置为<code>nil</code>。这使我们可以在闭包内检查它们是否存在。</p>
|
||||
<blockquote>
|
||||
<p>注意:</p>
|
||||
<p>如果捕获的引用绝对不会置为<code>nil</code>,应该用无主引用,而不是弱引用。</p>
|
||||
<p>注意:<br>如果捕获的引用绝对不会置为<code>nil</code>,应该用无主引用,而不是弱引用。</p>
|
||||
</blockquote>
|
||||
<p>前面的<code>HTMLElement</code>例子中,无主引用是正确的解决循环强引用的方法。这样编写<code>HTMLElement</code>类来避免循环强引用:</p>
|
||||
<pre><code>class HTMLElement {
|
||||
<pre><code class="lang-swift">class HTMLElement {
|
||||
|
||||
let name: String
|
||||
let text: String?
|
||||
@ -930,18 +944,21 @@ println(paragraph!.asHTML())
|
||||
}
|
||||
|
||||
}
|
||||
</code></pre><p>上面的<code>HTMLElement</code>实现和之前的实现一致,只是在<code>asHTML</code>闭包中多了一个捕获列表。这里,捕获列表是<code>[unowned self]</code>,表示“用无主引用而不是强引用来捕获<code>self</code>”。</p>
|
||||
</code></pre>
|
||||
<p>上面的<code>HTMLElement</code>实现和之前的实现一致,只是在<code>asHTML</code>闭包中多了一个捕获列表。这里,捕获列表是<code>[unowned self]</code>,表示“用无主引用而不是强引用来捕获<code>self</code>”。</p>
|
||||
<p>和之前一样,我们可以创建并打印<code>HTMLElement</code>实例:</p>
|
||||
<pre><code>var paragraph: HTMLElement? = HTMLElement(name: "p", text: "hello, world")
|
||||
<pre><code class="lang-swift">var paragraph: HTMLElement? = HTMLElement(name: "p", text: "hello, world")
|
||||
println(paragraph!.asHTML())
|
||||
// prints "<p>hello, world</p>"
|
||||
</code></pre><p>使用捕获列表后引用关系如下图所示:</p>
|
||||
</code></pre>
|
||||
<p>使用捕获列表后引用关系如下图所示:</p>
|
||||
<p><img src="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/closureReferenceCycle02_2x.png" alt=""></p>
|
||||
<p>这一次,闭包以无主引用的形式捕获<code>self</code>,并不会持有<code>HTMLElement</code>实例的强引用。如果将<code>paragraph</code>赋值为<code>nil</code>,<code>HTMLElement</code>实例将会被销毁,并能看到它的析构函数打印出的消息。</p>
|
||||
<pre><code>paragraph = nil
|
||||
<pre><code class="lang-swift">paragraph = nil
|
||||
// prints "p is being deinitialized"
|
||||
</code></pre>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
</div>
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="2.17" data-basepath=".." data-revision="1402750255397">
|
||||
<div class="book" data-level="2.17" data-basepath=".." data-revision="1402759431779">
|
||||
<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,11 +587,10 @@
|
||||
|
||||
<div class="page-inner">
|
||||
|
||||
<section class="normal" id="section-gitbook_66">
|
||||
<section class="normal" id="section-gitbook_542">
|
||||
|
||||
<blockquote>
|
||||
<p>翻译:Jasonbroker</p>
|
||||
<p>校对:numbbbbb</p>
|
||||
<p>翻译:Jasonbroker<br>校对:numbbbbb, stanzhai </p>
|
||||
</blockquote>
|
||||
<h1 id="optional-chaining">Optional Chaining</h1>
|
||||
<hr>
|
||||
@ -607,8 +606,7 @@
|
||||
</ul>
|
||||
<p>可选链(Optional Chaining)是一种可以请求和调用属性、方法及子脚本的过程,它的可选性体现于请求或调用的目标当前可能为空(<code>nil</code>)。如果可选的目标有值,那么调用就会成功;相反,如果选择的目标为空(<code>nil</code>),则这种调用将返回空(<code>nil</code>)。多次请求或调用可以被链接在一起形成一个链,如果任何一个节点为空(<code>nil</code>)将导致整个链失效。</p>
|
||||
<blockquote>
|
||||
<p>注意:
|
||||
Swift 的可选链和 Objective-C 中的消息为空有些相像,但是 Swift 可以使用在任意类型中,并且失败与否可以被检测到。</p>
|
||||
<p>注意:<br>Swift 的可选链和 Objective-C 中的消息为空有些相像,但是 Swift 可以使用在任意类型中,并且失败与否可以被检测到。</p>
|
||||
</blockquote>
|
||||
<p><a name="optional_chaining_as_an_alternative_to_forced_unwrapping"></a></p>
|
||||
<h2 id="-">可选链可替代强制解析</h2>
|
||||
@ -617,49 +615,56 @@ Swift 的可选链和 Objective-C 中的消息为空有些相像,但是 Swift
|
||||
<p>调用可选链的返回结果与原本的返回结果具有相同的类型,但是原本的返回结果被包装成了一个可选值,当可选链调用成功时,一个应该返回<code>Int</code>的属性将会返回<code>Int?</code>。</p>
|
||||
<p>下面几段代码将解释可选链和强制解析的不同。</p>
|
||||
<p>首先定义两个类<code>Person</code>和<code>Residence</code>。</p>
|
||||
<pre><code>class Person {
|
||||
<pre><code class="lang-swift">class Person {
|
||||
var residence: Residence?
|
||||
}
|
||||
|
||||
class Residence {
|
||||
var numberOfRooms = 1
|
||||
}
|
||||
</code></pre><p><code>Residence</code>具有一个<code>Int</code>类型的<code>numberOfRooms</code>,其值为 1。<code>Person</code>具有一个可选<code>residence</code>属性,它的类型是<code>Residence?</code>。</p>
|
||||
</code></pre>
|
||||
<p><code>Residence</code>具有一个<code>Int</code>类型的<code>numberOfRooms</code>,其值为 1。<code>Person</code>具有一个可选<code>residence</code>属性,它的类型是<code>Residence?</code>。</p>
|
||||
<p>如果你创建一个新的<code>Person</code>实例,它的<code>residence</code>属性由于是被定义为可选型的,此属性将默认初始化为空:</p>
|
||||
<pre><code>let john = Person()
|
||||
</code></pre><p>如果你想使用感叹号(<code>!</code>)强制解析获得这个人<code>residence</code>属性<code>numberOfRooms</code>属性值,将会引发运行时错误,因为这时没有可以供解析的<code>residence</code>值。</p>
|
||||
<pre><code>let roomCount = john.residence!.numberOfRooms
|
||||
<pre><code class="lang-swift">let john = Person()
|
||||
</code></pre>
|
||||
<p>如果你想使用感叹号(<code>!</code>)强制解析获得这个人<code>residence</code>属性<code>numberOfRooms</code>属性值,将会引发运行时错误,因为这时没有可以供解析的<code>residence</code>值。</p>
|
||||
<pre><code class="lang-swift">let roomCount = john.residence!.numberOfRooms
|
||||
//将导致运行时错误
|
||||
</code></pre><p>当<code>john.residence</code>不是<code>nil</code>时,会运行通过,且会将<code>roomCount</code> 设置为一个<code>int</code>类型的合理值。然而,如上所述,当<code>residence</code>为空时,这个代码将会导致运行时错误。</p>
|
||||
</code></pre>
|
||||
<p>当<code>john.residence</code>不是<code>nil</code>时,会运行通过,且会将<code>roomCount</code> 设置为一个<code>int</code>类型的合理值。然而,如上所述,当<code>residence</code>为空时,这个代码将会导致运行时错误。</p>
|
||||
<p>可选链提供了一种另一种获得<code>numberOfRooms</code>的方法。利用可选链,使用问号来代替原来<code>!</code>的位置:</p>
|
||||
<pre><code>if let roomCount = john.residence?.numberOfRooms {
|
||||
<pre><code class="lang-swift">if let roomCount = john.residence?.numberOfRooms {
|
||||
println("John's residence has \(roomCount) room(s).")
|
||||
} else {
|
||||
println("Unable to retrieve the number of rooms.")
|
||||
}
|
||||
// 打印 "Unable to retrieve the number of rooms.
|
||||
</code></pre><p>这告诉 Swift 来链接可选<code>residence?</code>属性,如果<code>residence</code>存在则取回<code>numberOfRooms</code>的值。</p>
|
||||
</code></pre>
|
||||
<p>这告诉 Swift 来链接可选<code>residence?</code>属性,如果<code>residence</code>存在则取回<code>numberOfRooms</code>的值。</p>
|
||||
<p>因为这种尝试获得<code>numberOfRooms</code>的操作有可能失败,可选链会返回<code>Int?</code>类型值,或者称作“可选<code>Int</code>”。当<code>residence</code>是空的时候(上例),选择<code>Int</code>将会为空,因此会出先无法访问<code>numberOfRooms</code>的情况。</p>
|
||||
<p>要注意的是,即使numberOfRooms是非可选<code>Int</code>(<code>Int?</code>)时这一点也成立。只要是通过可选链的请求就意味着最后<code>numberOfRooms</code>总是返回一个<code>Int?</code>而不是<code>Int</code>。</p>
|
||||
<p>你可以自己定义一个<code>Residence</code>实例给<code>john.residence</code>,这样它就不再为空了:</p>
|
||||
<pre><code>john.residence = Residence()
|
||||
</code></pre><p><code>john.residence</code> 现在有了实际存在的实例而不是nil了。如果你想使用和前面一样的可选链来获得<code>numberOfRoooms</code>,它将返回一个包含默认值 1 的<code>Int?</code>:</p>
|
||||
<pre><code>if let roomCount = john.residence?.numberOfRooms {
|
||||
<pre><code class="lang-swift">john.residence = Residence()
|
||||
</code></pre>
|
||||
<p><code>john.residence</code> 现在有了实际存在的实例而不是nil了。如果你想使用和前面一样的可选链来获得<code>numberOfRoooms</code>,它将返回一个包含默认值 1 的<code>Int?</code>:</p>
|
||||
<pre><code class="lang-swift">if let roomCount = john.residence?.numberOfRooms {
|
||||
println("John's residence has \(roomCount) room(s).")
|
||||
} else {
|
||||
println("Unable to retrieve the number of rooms.")
|
||||
}
|
||||
// 打印 "John's residence has 1 room(s)"。
|
||||
</code></pre><p><a name="defining_model_classes_for_optional_chaining"></a></p>
|
||||
</code></pre>
|
||||
<p><a name="defining_model_classes_for_optional_chaining"></a></p>
|
||||
<h2 id="-">为可选链定义模型类</h2>
|
||||
<p>你可以使用可选链来多层调用属性,方法,和子脚本。这让你可以利用它们之间的复杂模型来获取更底层的属性,并检查是否可以成功获取此类底层属性。</p>
|
||||
<p>后面的代码定义了四个将在后面使用的模型类,其中包括多层可选链。这些类是由上面的<code>Person</code>和<code>Residence</code>模型通过添加一个<code>Room</code>和一个<code>Address</code>类拓展来。</p>
|
||||
<p><code>Person</code>类定义与之前相同。</p>
|
||||
<pre><code>class Person {
|
||||
<pre><code class="lang-swift">class Person {
|
||||
var residence: Residence?
|
||||
}
|
||||
</code></pre><p><code>Residence</code>类比之前复杂些。这次,它定义了一个变量 <code>rooms</code>,它被初始化为一个<code>Room[]</code>类型的空数组:</p>
|
||||
<pre><code>class Residence {
|
||||
</code></pre>
|
||||
<p><code>Residence</code>类比之前复杂些。这次,它定义了一个变量 <code>rooms</code>,它被初始化为一个<code>Room[]</code>类型的空数组:</p>
|
||||
<pre><code class="lang-swift">class Residence {
|
||||
var rooms = Room[]()
|
||||
var numberOfRooms: Int {
|
||||
return rooms.count
|
||||
@ -672,17 +677,19 @@ class Residence {
|
||||
}
|
||||
var address: Address?
|
||||
}
|
||||
</code></pre><p>因为<code>Residence</code>存储了一个<code>Room</code>实例的数组,它的<code>numberOfRooms</code>属性值不是一个固定的存储值,而是通过计算而来的。<code>numberOfRooms</code>属性值是由返回<code>rooms</code>数组的<code>count</code>属性值得到的。</p>
|
||||
</code></pre>
|
||||
<p>因为<code>Residence</code>存储了一个<code>Room</code>实例的数组,它的<code>numberOfRooms</code>属性值不是一个固定的存储值,而是通过计算而来的。<code>numberOfRooms</code>属性值是由返回<code>rooms</code>数组的<code>count</code>属性值得到的。</p>
|
||||
<p>为了能快速访问<code>rooms</code>数组,<code>Residence</code>定义了一个只读的子脚本,通过插入数组的元素角标就可以成功调用。如果该角标存在,子脚本则将该元素返回。</p>
|
||||
<p><code>Residence</code>中也提供了一个<code>printNumberOfRooms</code>的方法,即简单的打印房间个数。</p>
|
||||
<p>最后,<code>Residence</code>定义了一个可选属性叫<code>address</code>(<code>address?</code>)。<code>Address</code>类的属性将在后面定义。
|
||||
用于<code>rooms</code>数组的<code>Room</code>类是一个很简单的类,它只有一个<code>name</code>属性和一个设定<code>room</code>名的初始化器。</p>
|
||||
<pre><code>class Room {
|
||||
<pre><code class="lang-swift">class Room {
|
||||
let name: String
|
||||
init(name: String) { self.name = name }
|
||||
}
|
||||
</code></pre><p>这个模型中的最终类叫做<code>Address</code>。它有三个类型是<code>String?</code>的可选属性。前面两个可选属性<code>buildingName</code>和 <code>buildingNumber</code>作为地址的一部分,是定义某个建筑物的两种方式。第三个属性<code>street</code>,用于命名地址的街道名:</p>
|
||||
<pre><code>class Address {
|
||||
</code></pre>
|
||||
<p>这个模型中的最终类叫做<code>Address</code>。它有三个类型是<code>String?</code>的可选属性。前面两个可选属性<code>buildingName</code>和 <code>buildingNumber</code>作为地址的一部分,是定义某个建筑物的两种方式。第三个属性<code>street</code>,用于命名地址的街道名:</p>
|
||||
<pre><code class="lang-swift">class Address {
|
||||
var buildingName: String?
|
||||
var buildingNumber: String?
|
||||
var street: String?
|
||||
@ -696,51 +703,55 @@ class Residence {
|
||||
}
|
||||
}
|
||||
}
|
||||
</code></pre><p><code>Address</code>类还提供了一个<code>buildingIdentifier</code>的方法,它的返回值类型为<code>String?</code>。这个方法检查<code>buildingName</code>和<code>buildingNumber</code>的属性,如果<code>buildingName</code>有值则将其返回,或者如果<code>buildingNumber</code>有值则将其返回,再或如果没有一个属性有值,返回空。</p>
|
||||
</code></pre>
|
||||
<p><code>Address</code>类还提供了一个<code>buildingIdentifier</code>的方法,它的返回值类型为<code>String?</code>。这个方法检查<code>buildingName</code>和<code>buildingNumber</code>的属性,如果<code>buildingName</code>有值则将其返回,或者如果<code>buildingNumber</code>有值则将其返回,再或如果没有一个属性有值,返回空。</p>
|
||||
<p><a name="calling_properties_through_optional_chaining"></a></p>
|
||||
<h2 id="-">通过可选链调用属性</h2>
|
||||
<p>正如上面“ <a href="#optional_chaining_as_an_alternative_to_forced_unwrapping">可选链可替代强制解析</a>”中所述,你可以利用可选链的可选值获取属性,并且检查属性是否获取成功。然而,你不能使用可选链为属性赋值。</p>
|
||||
<p>使用上述定义的类来创建一个人实例,并再次尝试后去它的<code>numberOfRooms</code>属性:</p>
|
||||
<pre><code>let john = Person()
|
||||
<pre><code class="lang-swift">let john = Person()
|
||||
if let roomCount = john.residence?.numberOfRooms {
|
||||
println("John's residence has \(roomCount) room(s).")
|
||||
} else {
|
||||
println("Unable to retrieve the number of rooms.")
|
||||
}
|
||||
// 打印 "Unable to retrieve the number of rooms。
|
||||
</code></pre><p>由于<code>john.residence</code>是空,所以这个可选链和之前一样失败了,但是没有运行时错误。</p>
|
||||
</code></pre>
|
||||
<p>由于<code>john.residence</code>是空,所以这个可选链和之前一样失败了,但是没有运行时错误。</p>
|
||||
<p><a name="calling_methods_through_optional_chaining"></a></p>
|
||||
<h2 id="-">通过可选链调用方法</h2>
|
||||
<p>你可以使用可选链的来调用可选值的方法并检查方法调用是否成功。即使这个方法没有返回值,你依然可以使用可选链来达成这一目的。</p>
|
||||
<p><code>Residence</code>的<code>printNumberOfRooms</code>方法会打印<code>numberOfRooms</code>的当前值。方法如下:</p>
|
||||
<pre><code>func printNumberOfRooms(){
|
||||
<pre><code class="lang-swift">func printNumberOfRooms(){
|
||||
println(“The number of rooms is \(numberOfRooms)”)
|
||||
}
|
||||
</code></pre><p>这个方法没有返回值。但是,没有返回值类型的函数和方法有一个隐式的返回值类型<code>Void</code>(参见Function Without Return Values)。</p>
|
||||
</code></pre>
|
||||
<p>这个方法没有返回值。但是,没有返回值类型的函数和方法有一个隐式的返回值类型<code>Void</code>(参见Function Without Return Values)。</p>
|
||||
<p>如果你利用可选链调用此方法,这个方法的返回值类型将是<code>Void?</code>,而不是<code>Void</code>,因为当通过可选链调用方法时返回值总是可选类型(optional type)。即使这个方法本身没有定义返回值,你也可以使用<code>if</code>语句来检查是否能成功调用<code>printNumberOfRooms</code>方法:如果方法通过可选链调用成功,<code>printNumberOfRooms</code>的隐式返回值将会是<code>Void</code>,如果没有成功,将返回<code>nil</code>:</p>
|
||||
<pre><code>if john.residence?.printNumberOfRooms() {
|
||||
<pre><code class="lang-swift">if john.residence?.printNumberOfRooms() {
|
||||
println("It was possible to print the number of rooms.")
|
||||
} else {
|
||||
println("It was not possible to print the number of rooms.")
|
||||
}
|
||||
// 打印 "It was not possible to print the number of rooms."。
|
||||
</code></pre><p><a name="calling_subscripts_through_optional_chaining"></a></p>
|
||||
</code></pre>
|
||||
<p><a name="calling_subscripts_through_optional_chaining"></a></p>
|
||||
<h2 id="-">使用可选链调用子脚本</h2>
|
||||
<p>你可以使用可选链来尝试从子脚本获取值并检查子脚本的调用是否成功,然而,你不能通过可选链来设置子代码。</p>
|
||||
<blockquote>
|
||||
<p>注意:
|
||||
当你使用可选链来获取子脚本的时候,你应该将问号放在子脚本括号的前面而不是后面。可选链的问号一般直接跟在表达语句的后面。</p>
|
||||
<p>注意:<br>当你使用可选链来获取子脚本的时候,你应该将问号放在子脚本括号的前面而不是后面。可选链的问号一般直接跟在表达语句的后面。</p>
|
||||
</blockquote>
|
||||
<p>下面这个例子用在<code>Residence</code>类中定义的子脚本来获取<code>john.residence</code>数组中第一个房间的名字。因为<code>john.residence</code>现在是<code>nil</code>,子脚本的调用失败了。</p>
|
||||
<pre><code>if let firstRoomName = john.residence?[0].name {
|
||||
<pre><code class="lang-swift">if let firstRoomName = john.residence?[0].name {
|
||||
println("The first room name is \(firstRoomName).")
|
||||
} else {
|
||||
println("Unable to retrieve the first room name.")
|
||||
}
|
||||
// 打印 "Unable to retrieve the first room name."。
|
||||
</code></pre><p>在子代码调用中可选链的问号直接跟在<code>john.residence</code>的后面,在子脚本括号的前面,因为<code>john.residence</code>是可选链试图获得的可选值。</p>
|
||||
</code></pre>
|
||||
<p>在子代码调用中可选链的问号直接跟在<code>john.residence</code>的后面,在子脚本括号的前面,因为<code>john.residence</code>是可选链试图获得的可选值。</p>
|
||||
<p>如果你创建一个<code>Residence</code>实例给<code>john.residence</code>,且在他的<code>rooms</code>数组中有一个或多个<code>Room</code>实例,那么你可以使用可选链通过<code>Residence</code>子脚本来获取在<code>rooms</code>数组中的实例了:</p>
|
||||
<pre><code>let johnsHouse = Residence()
|
||||
<pre><code class="lang-swift">let johnsHouse = Residence()
|
||||
johnsHouse.rooms += Room(name: "Living Room")
|
||||
johnsHouse.rooms += Room(name: "Kitchen")
|
||||
john.residence = johnsHouse
|
||||
@ -751,7 +762,8 @@ if let firstRoomName = john.residence?[0].name {
|
||||
println("Unable to retrieve the first room name.")
|
||||
}
|
||||
// 打印 "The first room name is Living Room."。
|
||||
</code></pre><p><a name="linking_multiple_levels_of_chaining"></a></p>
|
||||
</code></pre>
|
||||
<p><a name="linking_multiple_levels_of_chaining"></a></p>
|
||||
<h2 id="-">连接多层链接</h2>
|
||||
<p>你可以将多层可选链连接在一起,可以掘取模型内更下层的属性方法和子脚本。然而多层可选链不能再添加比已经返回的可选值更多的层。
|
||||
也就是说:</p>
|
||||
@ -761,43 +773,46 @@ if let firstRoomName = john.residence?[0].name {
|
||||
<p>如果你试图通过可选链获得<code>Int</code>值,不论使用了多少层链接返回的总是<code>Int?</code>。
|
||||
相似的,如果你试图通过可选链获得<code>Int?</code>值,不论使用了多少层链接返回的总是<code>Int?</code>。</p>
|
||||
<p>下面的例子试图获取<code>john</code>的<code>residence</code>属性里的<code>address</code>的<code>street</code>属性。这里使用了两层可选链来联系<code>residence</code>和<code>address</code>属性,它们两者都是可选类型:</p>
|
||||
<pre><code>if let johnsStreet = john.residence?.address?.street {
|
||||
<pre><code class="lang-swift">if let johnsStreet = john.residence?.address?.street {
|
||||
println("John's street name is \(johnsStreet).")
|
||||
} else {
|
||||
println("Unable to retrieve the address.")
|
||||
}
|
||||
// 打印 "Unable to retrieve the address.”。
|
||||
</code></pre><p><code>john.residence</code>的值现在包含一个<code>Residence</code>实例,然而<code>john.residence.address</code>现在是<code>nil</code>,因此<code>john.residence?.address?.street</code>调用失败。</p>
|
||||
</code></pre>
|
||||
<p><code>john.residence</code>的值现在包含一个<code>Residence</code>实例,然而<code>john.residence.address</code>现在是<code>nil</code>,因此<code>john.residence?.address?.street</code>调用失败。</p>
|
||||
<p>从上面的例子发现,你试图获得<code>street</code>属性值。这个属性的类型是<code>String?</code>。因此尽管在可选类型属性前使用了两层可选链,<code>john.residence?.address?.street</code>的返回值类型也是<code>String?</code>。</p>
|
||||
<p>如果你为<code>Address</code>设定一个实例来作为<code>john.residence.address</code>的值,并为<code>address</code>的<code>street</code>属性设定一个实际值,你可以通过多层可选链来得到这个属性值。</p>
|
||||
<pre><code>let johnsAddress = Address()
|
||||
<pre><code class="lang-swift">let johnsAddress = Address()
|
||||
johnsAddress.buildingName = "The Larches"
|
||||
johnsAddress.street = "Laurel Street"
|
||||
john.residence!.address = johnsAddress
|
||||
|
||||
if let johnsStreet = john.residence?.address?.street {
|
||||
</code></pre>
|
||||
<pre><code class="lang-swift">if let johnsStreet = john.residence?.address?.street {
|
||||
println("John's street name is \(johnsStreet).")
|
||||
} else {
|
||||
println("Unable to retrieve the address.")
|
||||
}
|
||||
// 打印 "John's street name is Laurel Street."。
|
||||
</code></pre><p>值得注意的是,“<code>!</code>”符号在给<code>john.residence.address</code>分配<code>address</code>实例时的使用。<code>john.residence</code>属性是一个可选类型,因此你需要在它获取<code>address</code>属性之前使用<code>!</code>解析以获得它的实际值。</p>
|
||||
</code></pre>
|
||||
<p>值得注意的是,“<code>!</code>”符号在给<code>john.residence.address</code>分配<code>address</code>实例时的使用。<code>john.residence</code>属性是一个可选类型,因此你需要在它获取<code>address</code>属性之前使用<code>!</code>解析以获得它的实际值。</p>
|
||||
<p><a name="chaining_on_methods_with_optional_return_values"></a></p>
|
||||
<h2 id="-">链接可选返回值的方法</h2>
|
||||
<p>前面的例子解释了如何通过可选链来获得可选类型属性值。你也可以通过可选链调用一个返回可选类型值的方法并按需链接该方法的返回值。</p>
|
||||
<p>下面的例子通过可选链调用了<code>Address</code>类中的<code>buildingIdentifier</code> 方法。这个方法的返回值类型是<code>String?</code>。如上所述,这个方法在可选链调用后最终的返回值类型依然是<code>String?</code>:</p>
|
||||
<pre><code>if let buildingIdentifier = john.residence?.address?.buildingIdentifier() {
|
||||
<pre><code class="lang-swift">if let buildingIdentifier = john.residence?.address?.buildingIdentifier() {
|
||||
println("John's building identifier is \(buildingIdentifier).")
|
||||
}
|
||||
// 打印 "John's building identifier is The Larches."。
|
||||
</code></pre><p>如果你还想进一步对方法返回值执行可选链,将可选链问号符放在方法括号的后面:</p>
|
||||
<pre><code>if let upper = john.residence?.address?.buildingIdentifier()?.uppercaseString {
|
||||
</code></pre>
|
||||
<p>如果你还想进一步对方法返回值执行可选链,将可选链问号符放在方法括号的后面:</p>
|
||||
<pre><code class="lang-swift">if let upper = john.residence?.address?.buildingIdentifier()?.uppercaseString {
|
||||
println("John's uppercase building identifier is \(upper).")
|
||||
}
|
||||
// 打印 "John's uppercase building identifier is THE LARCHES."。
|
||||
</code></pre><blockquote>
|
||||
<p>注意:
|
||||
在上面的例子中,你将可选链问号符放在括号后面是因为你想要链接的可选值是<code>buildingIdentifier</code>方法的返回值,不是<code>buildingIdentifier</code>方法本身。</p>
|
||||
</code></pre>
|
||||
<blockquote>
|
||||
<p>注意:<br>在上面的例子中,你将可选链问号符放在括号后面是因为你想要链接的可选值是<code>buildingIdentifier</code>方法的返回值,不是<code>buildingIdentifier</code>方法本身。</p>
|
||||
</blockquote>
|
||||
|
||||
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="2.18" data-basepath=".." data-revision="1402750255397">
|
||||
<div class="book" data-level="2.18" data-basepath=".." data-revision="1402759431779">
|
||||
<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,36 +587,36 @@
|
||||
|
||||
<div class="page-inner">
|
||||
|
||||
<section class="normal" id="section-gitbook_68">
|
||||
<section class="normal" id="section-gitbook_544">
|
||||
|
||||
<blockquote>
|
||||
<p>翻译:xiehurricane</p>
|
||||
<p>校对:happyming</p>
|
||||
<p>翻译:xiehurricane<br>校对:happyming </p>
|
||||
</blockquote>
|
||||
<h1 id="-type-casting-">类型转换(Type Casting)</h1>
|
||||
<h1 id="-type-casting-">类型检查(Type Casting)</h1>
|
||||
<hr>
|
||||
<p>本页包含内容:</p>
|
||||
<ul>
|
||||
<li><a href="#defining_a_class_hierarchy_for_type_casting">定义一个类层次作为例子</a></li>
|
||||
<li><a href="#checking_type">检查类型</a></li>
|
||||
<li><a href="#downcasting">向下转型(Downcasting)</a></li>
|
||||
<li><a href="#type_casting_for_any_and_anyobject"><code>Any</code>和<code>AnyObject</code>的类型转换</a></li>
|
||||
<li><a href="#type_casting_for_any_and_anyobject"><code>Any</code>和<code>AnyObject</code>的类型检查</a></li>
|
||||
</ul>
|
||||
<p> <em>类型检查</em>是一种检查类实例的方式,并且或者也是让实例作为它的父类或者子类的一种方式。</p>
|
||||
<p> 类型检查在 Swift 中使用<code>is</code> 和 <code>as</code>操作符实现。这两个操作符提供了一种简单达意的方式去检查值的类型或者转换它的类型。</p>
|
||||
<p> 你也可以用来检查一个类是否实现了某个协议,就像在 <a href="Protocols.html#//apple_ref/doc/uid/TP40014097-CH25-XID_363">Checking for Protocol Conformance</a>部分讲述的一样。</p>
|
||||
<p><em>类型检查</em>是一种检查类实例的方式,并且或者也是让实例作为它的父类或者子类的一种方式。</p>
|
||||
<p>类型检查在 Swift 中使用<code>is</code> 和 <code>as</code>操作符实现。这两个操作符提供了一种简单达意的方式去检查值的类型或者转换它的类型。</p>
|
||||
<p>你也可以用来检查一个类是否实现了某个协议,就像在 <a href="Protocols.html#//apple_ref/doc/uid/TP40014097-CH25-XID_363">Checking for Protocol Conformance</a>部分讲述的一样。</p>
|
||||
<p><a name="defining_a_class_hierarchy_for_type_casting"></a></p>
|
||||
<h2 id="-">定义一个类层次作为例子</h2>
|
||||
<p> 你可以将它用在类和子类的层次结构上,检查特定类实例的类型并且转换这个类实例的类型成为这个层次结构中的其他类型。这下面的三个代码段定义了一个类层次和一个包含了几个这些类实例的数组,作为类型检查的例子。</p>
|
||||
<p> 第一个代码片段定义了一个新的基础类<code>MediaItem</code>。这个类为任何出现在数字媒体库的媒体项提供基础功能。特别的,它声明了一个 <code>String</code> 类型的 <code>name</code> 属性,和一个<code>init name</code>初始化器。(它假定所有的媒体项都有个名称。)</p>
|
||||
<pre><code>class MediaItem {
|
||||
<p>你可以将它用在类和子类的层次结构上,检查特定类实例的类型并且转换这个类实例的类型成为这个层次结构中的其他类型。这下面的三个代码段定义了一个类层次和一个包含了几个这些类实例的数组,作为类型检查的例子。</p>
|
||||
<p>第一个代码片段定义了一个新的基础类<code>MediaItem</code>。这个类为任何出现在数字媒体库的媒体项提供基础功能。特别的,它声明了一个 <code>String</code> 类型的 <code>name</code> 属性,和一个<code>init name</code>初始化器。(它假定所有的媒体项都有个名称。)</p>
|
||||
<pre><code class="lang-swift">class MediaItem {
|
||||
var name: String
|
||||
init(name: String) {
|
||||
self.name = name
|
||||
}
|
||||
}
|
||||
</code></pre><p> 下一个代码段定义了 <code>MediaItem</code> 的两个子类。第一个子类<code>Movie</code>,在父类(或者说基类)的基础上增加了一个 <code>director</code>(导演) 属性,和相应的初始化器。第二个类在父类的基础上增加了一个 <code>artist</code>(艺术家) 属性,和相应的初始化器:</p>
|
||||
<pre><code>class Movie: MediaItem {
|
||||
</code></pre>
|
||||
<p>下一个代码段定义了 <code>MediaItem</code> 的两个子类。第一个子类<code>Movie</code>,在父类(或者说基类)的基础上增加了一个 <code>director</code>(导演) 属性,和相应的初始化器。第二个类在父类的基础上增加了一个 <code>artist</code>(艺术家) 属性,和相应的初始化器:</p>
|
||||
<pre><code class="lang-swift">class Movie: MediaItem {
|
||||
var director: String
|
||||
init(name: String, director: String) {
|
||||
self.director = director
|
||||
@ -631,9 +631,9 @@ class Song: MediaItem {
|
||||
super.init(name: name)
|
||||
}
|
||||
}
|
||||
</code></pre><p> 最后一个代码段创建了一个数组常量 <code>library</code>
|
||||
,包含两个<code>Movie</code>实例和三个<code>Song</code>实例。<code>library</code>的类型是在它被初始化时根据它数组中所包含的内容推断来的。Swift 的类型检测器能够演绎出<code>Movie</code> 和 <code>Song</code> 有共同的父类 <code>MediaItem</code> ,所以它推断出 <code>MediaItem[]</code> 类作为 <code>library</code> 的类型。</p>
|
||||
<pre><code>let library = [
|
||||
</code></pre>
|
||||
<p>最后一个代码段创建了一个数组常量 <code>library</code>,包含两个<code>Movie</code>实例和三个<code>Song</code>实例。<code>library</code>的类型是在它被初始化时根据它数组中所包含的内容推断来的。Swift 的类型检测器能够演绎出<code>Movie</code> 和 <code>Song</code> 有共同的父类 <code>MediaItem</code> ,所以它推断出 <code>MediaItem[]</code> 类作为 <code>library</code> 的类型。</p>
|
||||
<pre><code class="lang-swift">let library = [
|
||||
Movie(name: "Casablanca", director: "Michael Curtiz"),
|
||||
Song(name: "Blue Suede Shoes", artist: "Elvis Presley"),
|
||||
Movie(name: "Citizen Kane", director: "Orson Welles"),
|
||||
@ -641,12 +641,13 @@ class Song: MediaItem {
|
||||
Song(name: "Never Gonna Give You Up", artist: "Rick Astley")
|
||||
]
|
||||
// the type of "library" is inferred to be MediaItem[]
|
||||
</code></pre><p> 在幕后<code>library</code> 里存储的媒体项依然是 <code>Movie</code> 和 <code>Song</code> 类型的,但是,若你迭代它,取出的实例会是 <code>MediaItem</code> 类型的,而不是 <code>Movie</code> 和 <code>Song</code> 类型的。为了让它们作为它们本来的类型工作,你需要检查它们的类型或者向下转换它们的类型到其它类型,就像下面描述的一样。</p>
|
||||
</code></pre>
|
||||
<p>在幕后<code>library</code> 里存储的媒体项依然是 <code>Movie</code> 和 <code>Song</code> 类型的,但是,若你迭代它,取出的实例会是 <code>MediaItem</code> 类型的,而不是 <code>Movie</code> 和 <code>Song</code> 类型的。为了让它们作为它们本来的类型工作,你需要检查它们的类型或者向下转换它们的类型到其它类型,就像下面描述的一样。</p>
|
||||
<p><a name="checking_type"></a></p>
|
||||
<h2 id="-">检查类型</h2>
|
||||
<p> 用类型检查操作符(<code>is</code>)来检查一个实例是否属于特定子类型。若实例属于那个子类型,类型检查操作符返回 <code>true</code> ,否则返回 <code>false</code> 。</p>
|
||||
<p> 下面的例子定义了两个变量,<code>movieCount</code> 和 <code>songCount</code>,用来计算数组<code>library</code> 中 <code>Movie</code> 和 <code>Song</code> 类型的实例数量。</p>
|
||||
<pre><code>var movieCount = 0
|
||||
<h2 id="-checking-type-">检查类型(Checking Type)</h2>
|
||||
<p>用类型检查操作符(<code>is</code>)来检查一个实例是否属于特定子类型。若实例属于那个子类型,类型检查操作符返回 <code>true</code> ,否则返回 <code>false</code> 。</p>
|
||||
<p>下面的例子定义了两个变量,<code>movieCount</code> 和 <code>songCount</code>,用来计算数组<code>library</code> 中 <code>Movie</code> 和 <code>Song</code> 类型的实例数量。</p>
|
||||
<pre><code class="lang-swift">var movieCount = 0
|
||||
var songCount = 0
|
||||
|
||||
for item in library {
|
||||
@ -659,20 +660,21 @@ for item in library {
|
||||
|
||||
println("Media library contains \(movieCount) movies and \(songCount) songs")
|
||||
// prints "Media library contains 2 movies and 3 songs"
|
||||
</code></pre><p> 示例迭代了数组 <code>library</code> 中的所有项。每一次, <code>for</code>-<code>in</code> 循环设置
|
||||
<code>item</code> 为数组中的下一个 <code>MediaItem</code>。</p>
|
||||
<p> 若当前 <code>MediaItem</code> 是一个 <code>Movie</code> 类型的实例, <code>item is Movie</code> 返回
|
||||
<code>true</code>,相反返回 <code>false</code>。同样的,<code>item is
|
||||
Song</code>检查item是否为<code>Song</code>类型的实例。在循环结束后,<code>movieCount</code> 和 <code>songCount</code>的值就是被找到属于各自的类型的实例数量。</p>
|
||||
</code></pre>
|
||||
<p>示例迭代了数组 <code>library</code> 中的所有项。每一次, <code>for</code>-<code>in</code> 循环设置
|
||||
<code>item</code> 为数组中的下一个 <code>MediaItem</code>。</p>
|
||||
<p>若当前 <code>MediaItem</code> 是一个 <code>Movie</code> 类型的实例, <code>item is Movie</code> 返回
|
||||
<code>true</code>,相反返回 <code>false</code>。同样的,<code>item is
|
||||
Song</code>检查item是否为<code>Song</code>类型的实例。在循环结束后,<code>movieCount</code> 和 <code>songCount</code>的值就是被找到属于各自的类型的实例数量。</p>
|
||||
<p><a name="downcasting"></a></p>
|
||||
<h2 id="-downcasting-">向下转型(Downcasting)</h2>
|
||||
<p> 某类型的一个常量或变量可能在幕后实际上属于一个子类。你可以相信,上面就是这种情况。你可以尝试向下转到它的子类型,用类型转换操作符(<code>as</code>)</p>
|
||||
<p> 因为向下转型可能会失败,类型转型操作符带有两种不同形式。可选形式( optional form) <code>as?</code> 返回一个你试图下转成的类型的可选值(optional value)。强制形式 <code>as</code> 把试图向下转型和强制解包(force-unwraps)结果作为一个混合动作。</p>
|
||||
<p> 当你不确定向下转型可以成功时,用类型转换的可选形式(<code>as?</code>)。可选形式的类型转换总是返回一个可选值(optional value),并且若下转是不可能的,可选值将是 <code>nil</code> 。这使你能够检查向下转型是否成功。</p>
|
||||
<p> 只有你可以确定向下转型一定会成功时,才使用强制形式。当你试图向下转型为一个不正确的类型时,强制形式的类型转换会触发一个运行时错误。</p>
|
||||
<p> 下面的例子,迭代了<code>library</code>里的每一个 <code>MediaItem</code> ,并打印出适当的描述。要这样做,<code>item</code>需要真正作为<code>Movie</code> 或 <code>Song</code>的类型来使用。不仅仅是作为 <code>MediaItem</code>。为了能够使用<code>Movie</code> 或 <code>Song</code>的 <code>director</code> 或 <code>artist</code>属性,这是必要的。</p>
|
||||
<p> 在这个示例中,数组中的每一个<code>item</code>可能是 <code>Movie</code> 或 <code>Song</code>。 事前你不知道每个<code>item</code>的真实类型,所以这里使用可选形式的类型转换 (<code>as?</code>)去检查循环里的每次下转。</p>
|
||||
<pre><code>for item in library {
|
||||
<p>某类型的一个常量或变量可能在幕后实际上属于一个子类。你可以相信,上面就是这种情况。你可以尝试向下转到它的子类型,用类型检查操作符(<code>as</code>)</p>
|
||||
<p>因为向下转型可能会失败,类型转型操作符带有两种不同形式。可选形式( optional form) <code>as?</code> 返回一个你试图下转成的类型的可选值(optional value)。强制形式 <code>as</code> 把试图向下转型和强制解包(force-unwraps)结果作为一个混合动作。</p>
|
||||
<p>当你不确定向下转型可以成功时,用类型检查的可选形式(<code>as?</code>)。可选形式的类型检查总是返回一个可选值(optional value),并且若下转是不可能的,可选值将是 <code>nil</code> 。这使你能够检查向下转型是否成功。</p>
|
||||
<p>只有你可以确定向下转型一定会成功时,才使用强制形式。当你试图向下转型为一个不正确的类型时,强制形式的类型检查会触发一个运行时错误。</p>
|
||||
<p>下面的例子,迭代了<code>library</code>里的每一个 <code>MediaItem</code> ,并打印出适当的描述。要这样做,<code>item</code>需要真正作为<code>Movie</code> 或 <code>Song</code>的类型来使用。不仅仅是作为 <code>MediaItem</code>。为了能够使用<code>Movie</code> 或 <code>Song</code>的 <code>director</code> 或 <code>artist</code>属性,这是必要的。</p>
|
||||
<p>在这个示例中,数组中的每一个<code>item</code>可能是 <code>Movie</code> 或 <code>Song</code>。 事前你不知道每个<code>item</code>的真实类型,所以这里使用可选形式的类型检查 (<code>as?</code>)去检查循环里的每次下转。</p>
|
||||
<pre><code class="lang-swift">for item in library {
|
||||
if let movie = item as? Movie {
|
||||
println("Movie: '\(movie.name)', dir. \(movie.director)")
|
||||
} else if let song = item as? Song {
|
||||
@ -685,58 +687,58 @@ println("Media library contains \(movieCount) movies and \(songCount) songs
|
||||
// Movie: 'Citizen Kane', dir. Orson Welles
|
||||
// Song: 'The One And Only', by Chesney Hawkes
|
||||
// Song: 'Never Gonna Give You Up', by Rick Astley
|
||||
</code></pre><p> 示例首先试图将 <code>item</code> 下转为 <code>Movie</code>。因为 <code>item</code> 是一个 <code>MediaItem</code>
|
||||
类型的实例,它可能是一个<code>Movie</code>;同样,它可能是一个 <code>Song</code>,或者仅仅是基类
|
||||
<code>MediaItem</code>。因为不确定,<code>as?</code>形式在试图下转时将返还一个可选值。 <code>item as Movie</code> 的返回值是<code>Movie?</code>类型或 “optional <code>Movie</code>”。</p>
|
||||
<p> 当向下转型为 <code>Movie</code> 应用在两个 <code>Song</code>
|
||||
实例时将会失败。为了处理这种情况,上面的例子使用了可选绑定(optional binding)来检查可选 <code>Movie</code>真的包含一个值(这个是为了判断下转是否成功。)可选绑定是这样写的“<code>if let movie = item as? Movie</code>”,可以这样解读:</p>
|
||||
<p> “尝试将 <code>item</code> 转为 <code>Movie</code>类型。若成功,设置一个新的临时常量 <code>movie</code> 来存储返回的可选<code>Movie</code>”</p>
|
||||
<p> 若向下转型成功,然后<code>movie</code>的属性将用于打印一个<code>Movie</code>实例的描述,包括它的导演的名字<code>director</code>。当<code>Song</code>被找到时,一个相近的原理被用来检测 <code>Song</code> 实例和打印它的描述。</p>
|
||||
</code></pre>
|
||||
<p>示例首先试图将 <code>item</code> 下转为 <code>Movie</code>。因为 <code>item</code> 是一个 <code>MediaItem</code>
|
||||
类型的实例,它可能是一个<code>Movie</code>;同样,它可能是一个 <code>Song</code>,或者仅仅是基类
|
||||
<code>MediaItem</code>。因为不确定,<code>as?</code>形式在试图下转时将返还一个可选值。 <code>item as Movie</code> 的返回值是<code>Movie?</code>类型或 “optional <code>Movie</code>”。</p>
|
||||
<p>当向下转型为 <code>Movie</code> 应用在两个 <code>Song</code>
|
||||
实例时将会失败。为了处理这种情况,上面的例子使用了可选绑定(optional binding)来检查可选 <code>Movie</code>真的包含一个值(这个是为了判断下转是否成功。)可选绑定是这样写的“<code>if let movie = item as? Movie</code>”,可以这样解读:</p>
|
||||
<p>“尝试将 <code>item</code> 转为 <code>Movie</code>类型。若成功,设置一个新的临时常量 <code>movie</code> 来存储返回的可选<code>Movie</code>”</p>
|
||||
<p>若向下转型成功,然后<code>movie</code>的属性将用于打印一个<code>Movie</code>实例的描述,包括它的导演的名字<code>director</code>。当<code>Song</code>被找到时,一个相近的原理被用来检测 <code>Song</code> 实例和打印它的描述。</p>
|
||||
<blockquote>
|
||||
<p>注意:</p>
|
||||
<p>转换没有真的改变实例或它的值。潜在的根本的实例保持不变;只是简单地把它作为它被转换成的类来使用。</p>
|
||||
<p>注意:<br>转换没有真的改变实例或它的值。潜在的根本的实例保持不变;只是简单地把它作为它被转换成的类来使用。</p>
|
||||
</blockquote>
|
||||
<p><a name="type_casting_for_any_and_anyobject"></a></p>
|
||||
<h2 id="-any-anyobject-"><code>Any</code>和<code>AnyObject</code>的类型转换</h2>
|
||||
<p> Swift为不确定类型提供了两种特殊类型别名:</p>
|
||||
<h2 id="-any-anyobject-"><code>Any</code>和<code>AnyObject</code>的类型检查</h2>
|
||||
<p>Swift为不确定类型提供了两种特殊类型别名:</p>
|
||||
<ul>
|
||||
<li><p><code>AnyObject</code>可以代表任何class类型的实例。</p>
|
||||
</li>
|
||||
<li><p><code>Any</code>可以表示任何类型,除了方法类型(function types)。</p>
|
||||
</li>
|
||||
<li><code>AnyObject</code>可以代表任何class类型的实例。</li>
|
||||
<li><code>Any</code>可以表示任何类型,除了方法类型(function types)。</li>
|
||||
</ul>
|
||||
<blockquote>
|
||||
<p>注意:</p>
|
||||
<p>只有当你明确的需要它的行为和功能时才使用<code>Any</code>和<code>AnyObject</code>。在你的代码里使用你期望的明确的类型总是更好的。</p>
|
||||
<p>注意:<br>只有当你明确的需要它的行为和功能时才使用<code>Any</code>和<code>AnyObject</code>。在你的代码里使用你期望的明确的类型总是更好的。</p>
|
||||
</blockquote>
|
||||
<h3 id="-anyobject-"><code>AnyObject</code>类型</h3>
|
||||
<p> 当需要在工作中使用 Cocoa
|
||||
APIs,它一般接收一个<code>AnyObject[]</code>类型的数组,或者说“一个任何对象类型的数组”。这是因为 Objective-C 没有明确的类型化数组。但是,你常常可以确定包含在仅从你知道的 API 信息提供的这样一个数组中的对象的类型。</p>
|
||||
<p> 在这些情况下,你可以使用强制形式的类型转换(<code>as</code>)来下转在数组中的每一项到比 <code>AnyObject</code> 更明确的类型,不需要可选解析(optional unwrapping)。</p>
|
||||
<p> 下面的示例定义了一个 <code>AnyObject[]</code> 类型的数组并填入三个<code>Movie</code>类型的实例:</p>
|
||||
<pre><code>let someObjects: AnyObject[] = [
|
||||
<p>当需要在工作中使用 Cocoa
|
||||
APIs,它一般接收一个<code>AnyObject[]</code>类型的数组,或者说“一个任何对象类型的数组”。这是因为 Objective-C 没有明确的类型化数组。但是,你常常可以确定包含在仅从你知道的 API 信息提供的这样一个数组中的对象的类型。</p>
|
||||
<p>在这些情况下,你可以使用强制形式的类型检查(<code>as</code>)来下转在数组中的每一项到比 <code>AnyObject</code> 更明确的类型,不需要可选解析(optional unwrapping)。</p>
|
||||
<p>下面的示例定义了一个 <code>AnyObject[]</code> 类型的数组并填入三个<code>Movie</code>类型的实例:</p>
|
||||
<pre><code class="lang-swift">let someObjects: AnyObject[] = [
|
||||
Movie(name: "2001: A Space Odyssey", director: "Stanley Kubrick"),
|
||||
Movie(name: "Moon", director: "Duncan Jones"),
|
||||
Movie(name: "Alien", director: "Ridley Scott")
|
||||
]
|
||||
</code></pre><p> 因为知道这个数组只包含 <code>Movie</code> 实例,你可以直接用(<code>as</code>)下转并解包到不可选的<code>Movie</code>类型(ps:其实就是我们常用的正常类型,这里是为了和可选类型相对比)。</p>
|
||||
<pre><code>for object in someObjects {
|
||||
</code></pre>
|
||||
<p>因为知道这个数组只包含 <code>Movie</code> 实例,你可以直接用(<code>as</code>)下转并解包到不可选的<code>Movie</code>类型(ps:其实就是我们常用的正常类型,这里是为了和可选类型相对比)。</p>
|
||||
<pre><code class="lang-swift">for object in someObjects {
|
||||
let movie = object as Movie
|
||||
println("Movie: '\(movie.name)', dir. \(movie.director)")
|
||||
}
|
||||
// Movie: '2001: A Space Odyssey', dir. Stanley Kubrick
|
||||
// Movie: 'Moon', dir. Duncan Jones
|
||||
// Movie: 'Alien', dir. Ridley Scott
|
||||
</code></pre><p> 为了变为一个更短的形式,下转<code>someObjects</code>数组为<code>Movie[]</code>类型来代替下转每一项方式。</p>
|
||||
<pre><code>for movie in someObjects as Movie[] {
|
||||
</code></pre>
|
||||
<p>为了变为一个更短的形式,下转<code>someObjects</code>数组为<code>Movie[]</code>类型来代替下转每一项方式。</p>
|
||||
<pre><code class="lang-swift">for movie in someObjects as Movie[] {
|
||||
println("Movie: '\(movie.name)', dir. \(movie.director)")
|
||||
}
|
||||
// Movie: '2001: A Space Odyssey', dir. Stanley Kubrick
|
||||
// Movie: 'Moon', dir. Duncan Jones
|
||||
// Movie: 'Alien', dir. Ridley Scott
|
||||
</code></pre><h3 id="-any-"><code>Any</code>类型</h3>
|
||||
<p> 这里有个示例,使用 <code>Any</code> 类型来和混合的不同类型一起工作,包括非<code>class</code>类型。它创建了一个可以存储<code>Any</code>类型的数组 <code>things</code>。</p>
|
||||
<pre><code>var things = Any[]()
|
||||
</code></pre>
|
||||
<h3 id="-any-"><code>Any</code>类型</h3>
|
||||
<p>这里有个示例,使用 <code>Any</code> 类型来和混合的不同类型一起工作,包括非<code>class</code>类型。它创建了一个可以存储<code>Any</code>类型的数组 <code>things</code>。</p>
|
||||
<pre><code class="lang-swift">var things = Any[]()
|
||||
|
||||
things.append(0)
|
||||
things.append(0.0)
|
||||
@ -745,9 +747,10 @@ things.append(3.14159)
|
||||
things.append("hello")
|
||||
things.append((3.0, 5.0))
|
||||
things.append(Movie(name: "Ghostbusters", director: "Ivan Reitman"))
|
||||
</code></pre><p> <code>things</code> 数组包含两个 <code>Int</code> 值,2个 <code>Double</code> 值,1个 <code>String</code> 值,一个元组 <code>(Double, Double)</code> ,Ivan Reitman 导演的电影“Ghostbusters”。</p>
|
||||
<p> 你可以在 <code>switch</code> <code>cases</code>里用<code>is</code> 和 <code>as</code> 操作符来发觉只知道是 <code>Any</code> 或 <code>AnyObject</code>的常量或变量的类型。 下面的示例迭代 <code>things</code>数组中的每一项的并用<code>switch</code>语句查找每一项的类型。这几种<code>switch</code>语句的情形绑定它们匹配的值到一个规定类型的常量,让它们可以打印它们的值:</p>
|
||||
<pre><code>for thing in things {
|
||||
</code></pre>
|
||||
<p><code>things</code> 数组包含两个 <code>Int</code> 值,2个 <code>Double</code> 值,1个 <code>String</code> 值,一个元组 <code>(Double, Double)</code> ,Ivan Reitman 导演的电影“Ghostbusters”。</p>
|
||||
<p>你可以在 <code>switch</code> <code>cases</code>里用<code>is</code> 和 <code>as</code> 操作符来发觉只知道是 <code>Any</code> 或 <code>AnyObject</code>的常量或变量的类型。 下面的示例迭代 <code>things</code>数组中的每一项的并用<code>switch</code>语句查找每一项的类型。这几种<code>switch</code>语句的情形绑定它们匹配的值到一个规定类型的常量,让它们可以打印它们的值:</p>
|
||||
<pre><code class="lang-swift">for thing in things {
|
||||
switch thing {
|
||||
case 0 as Int:
|
||||
println("zero as an Int")
|
||||
@ -777,10 +780,9 @@ things.append(Movie(name: "Ghostbusters", director: "Ivan Reitman
|
||||
// a string value of "hello"
|
||||
// an (x, y) point at 3.0, 5.0
|
||||
// a movie called 'Ghostbusters', dir. Ivan Reitman
|
||||
</code></pre><p>。</p>
|
||||
</code></pre>
|
||||
<blockquote>
|
||||
<p>注意:</p>
|
||||
<p>在一个switch语句的case中使用强制形式的类型转换操作符(as, 而不是 as?)来检查和转换到一个明确的类型。在 switch case 语句的内容中这种检查总是安全的。</p>
|
||||
<p>注意:<br>在一个switch语句的case中使用强制形式的类型检查操作符(as, 而不是 as?)来检查和转换到一个明确的类型。在 switch case 语句的内容中这种检查总是安全的。</p>
|
||||
</blockquote>
|
||||
|
||||
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="2.19" data-basepath=".." data-revision="1402750255397">
|
||||
<div class="book" data-level="2.19" data-basepath=".." data-revision="1402759431779">
|
||||
<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,11 +587,10 @@
|
||||
|
||||
<div class="page-inner">
|
||||
|
||||
<section class="normal" id="section-gitbook_70">
|
||||
<section class="normal" id="section-gitbook_546">
|
||||
|
||||
<blockquote>
|
||||
<p>翻译:Lin-H</p>
|
||||
<p>校对:shinyzhu</p>
|
||||
<p>翻译:Lin-H<br>校对:shinyzhu </p>
|
||||
</blockquote>
|
||||
<h1 id="-">类型嵌套</h1>
|
||||
<hr>
|
||||
@ -606,11 +605,12 @@
|
||||
<h2 id="-">类型嵌套实例</h2>
|
||||
<p>下面这个例子定义了一个结构体<code>BlackjackCard</code>(二十一点),用来模拟<code>BlackjackCard</code>中的扑克牌点数。<code>BlackjackCard</code>结构体包含2个嵌套定义的枚举类型<code>Suit</code> 和 <code>Rank</code>。</p>
|
||||
<p>在<code>BlackjackCard</code>规则中,<code>Ace</code>牌可以表示1或者11,<code>Ace</code>牌的这一特征用一个嵌套在枚举型<code>Rank</code>的结构体<code>Values</code>来表示。</p>
|
||||
<pre><code>struct BlackjackCard {
|
||||
<pre><code class="lang-swift">struct BlackjackCard {
|
||||
// 嵌套定义枚举型Suit
|
||||
enum Suit: Character {
|
||||
case Spades = "♠", Hearts = "♡", Diamonds = "♢", Clubs = "♣"
|
||||
}
|
||||
|
||||
// 嵌套定义枚举型Rank
|
||||
enum Rank: Int {
|
||||
case Two = 2, Three, Four, Five, Six, Seven, Eight, Nine, Ten
|
||||
@ -629,6 +629,7 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// BlackjackCard 的属性和方法
|
||||
let rank: Rank, suit: Suit
|
||||
var description: String {
|
||||
@ -640,7 +641,8 @@
|
||||
return output
|
||||
}
|
||||
}
|
||||
</code></pre><p>枚举型的<code>Suit</code>用来描述扑克牌的四种花色,并分别用一个<code>Character</code>类型的值代表花色符号。</p>
|
||||
</code></pre>
|
||||
<p>枚举型的<code>Suit</code>用来描述扑克牌的四种花色,并分别用一个<code>Character</code>类型的值代表花色符号。</p>
|
||||
<p>枚举型的<code>Rank</code>用来描述扑克牌从<code>Ace</code>~10,<code>J</code>,<code>Q</code>,<code>K</code>,13张牌,并分别用一个<code>Int</code>类型的值表示牌的面值。(这个<code>Int</code>类型的值不适用于<code>Ace</code>,<code>J</code>,<code>Q</code>,<code>K</code>的牌)。</p>
|
||||
<p>如上文所提到的,枚举型<code>Rank</code>在自己内部定义了一个嵌套结构体<code>Values</code>。这个结构体包含两个变量,只有<code>Ace</code>有两个数值,其余牌都只有一个数值。结构体<code>Values</code>中定义的两个属性:</p>
|
||||
<p><code>first</code>, 为<code>Int</code>
|
||||
@ -648,16 +650,19 @@
|
||||
<p><code>Rank</code>定义了一个计算属性<code>values</code>,这个计算属性会根据牌的面值,用适当的数值去初始化<code>Values</code>实例,并赋值给<code>values</code>。对于<code>J</code>,<code>Q</code>,<code>K</code>,<code>Ace</code>会使用特殊数值,对于数字面值的牌使用<code>Int</code>类型的值。</p>
|
||||
<p><code>BlackjackCard</code>结构体自身有两个属性—<code>rank</code>与<code>suit</code>,也同样定义了一个计算属性<code>description</code>,<code>description</code>属性用<code>rank</code>和<code>suit</code>的中内容来构建对这张扑克牌名字和数值的描述,并用可选类型<code>second</code>来检查是否存在第二个值,若存在,则在原有的描述中增加对第二数值的描述。</p>
|
||||
<p>因为<code>BlackjackCard</code>是一个没有自定义构造函数的结构体,在<a href="https://github.com/CocoaChina-editors/Welcome-to-Swift/blob/master/The%20Swift%20Programming%20Language/02Language%20Guide/14Initialization.md" target="_blank">Memberwise Initializers for Structure Types</a>中知道结构体有默认的成员构造函数,所以你可以用默认的<code>initializer</code>去初始化新的常量<code>theAceOfSpades</code>:</p>
|
||||
<pre><code>let theAceOfSpades = BlackjackCard(rank: .Ace, suit: .Spades)
|
||||
<pre><code class="lang-swift">let theAceOfSpades = BlackjackCard(rank: .Ace, suit: .Spades)
|
||||
println("theAceOfSpades: \(theAceOfSpades.description)")
|
||||
// 打印出 "theAceOfSpades: suit is ♠, value is 1 or 11"
|
||||
</code></pre><p>尽管<code>Rank</code>和<code>Suit</code>嵌套在<code>BlackjackCard</code>中,但仍可被引用,所以在初始化实例时能够通过枚举类型中的成员名称单独引用。在上面的例子中<code>description</code>属性能正确得输出对<code>Ace</code>牌有1和11两个值。</p>
|
||||
</code></pre>
|
||||
<p>尽管<code>Rank</code>和<code>Suit</code>嵌套在<code>BlackjackCard</code>中,但仍可被引用,所以在初始化实例时能够通过枚举类型中的成员名称单独引用。在上面的例子中<code>description</code>属性能正确得输出对<code>Ace</code>牌有1和11两个值。</p>
|
||||
<p><a name="referring_to_nested_types"></a></p>
|
||||
<h2 id="-">类型嵌套的引用</h2>
|
||||
<p>在外部对嵌套类型的引用,以被嵌套类型的名字为前缀,加上所要引用的属性名:</p>
|
||||
<pre><code>let heartsSymbol = BlackjackCard.Suit.Hearts.toRaw()
|
||||
<pre><code class="lang-swift">let heartsSymbol = BlackjackCard.Suit.Hearts.toRaw()
|
||||
// 红心的符号 为 "♡"
|
||||
</code></pre><p>对于上面这个例子,这样可以使<code>Suit</code>, <code>Rank</code>, 和 <code>Values</code>的名字尽可能的短,因为它们的名字会自然的由被定义的上下文来限定。</p>
|
||||
</code></pre>
|
||||
<p>对于上面这个例子,这样可以使<code>Suit</code>, <code>Rank</code>, 和 <code>Values</code>的名字尽可能的短,因为它们的名字会自然的由被定义的上下文来限定。</p>
|
||||
<p>preview</p>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="2.20" data-basepath=".." data-revision="1402750255397">
|
||||
<div class="book" data-level="2.20" data-basepath=".." data-revision="1402759431779">
|
||||
<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,11 +587,10 @@
|
||||
|
||||
<div class="page-inner">
|
||||
|
||||
<section class="normal" id="section-gitbook_72">
|
||||
<section class="normal" id="section-gitbook_548">
|
||||
|
||||
<blockquote>
|
||||
<p>翻译:lyuka</p>
|
||||
<p>校对:Hawstein</p>
|
||||
<p>翻译:lyuka<br>校对:Hawstein </p>
|
||||
</blockquote>
|
||||
<h1 id="-extensions-">扩展(Extensions)</h1>
|
||||
<hr>
|
||||
@ -615,24 +614,25 @@
|
||||
<li>使一个已有类型符合某个协议</li>
|
||||
</ul>
|
||||
<blockquote>
|
||||
<p>注意:</p>
|
||||
<p>如果你定义了一个扩展向一个已有类型添加新功能,那么这个新功能对该类型的所有已有实例中都是可用的,即使它们是在你的这个扩展的前面定义的。</p>
|
||||
<p>注意:<br>如果你定义了一个扩展向一个已有类型添加新功能,那么这个新功能对该类型的所有已有实例中都是可用的,即使它们是在你的这个扩展的前面定义的。</p>
|
||||
</blockquote>
|
||||
<p><a name="extension_syntax"></a></p>
|
||||
<h2 id="-extension-syntax-">扩展语法(Extension Syntax)</h2>
|
||||
<p>声明一个扩展使用关键字<code>extension</code>:</p>
|
||||
<pre><code>extension SomeType {
|
||||
<pre><code class="lang-swift">extension SomeType {
|
||||
// 加到SomeType的新功能写到这里
|
||||
}
|
||||
</code></pre><p>一个扩展可以扩展一个已有类型,使其能够适配一个或多个协议(protocol)。当这种情况发生时,协议的名字应该完全按照类或结构体的名字的方式进行书写:</p>
|
||||
<pre><code>extension SomeType: SomeProtocol, AnotherProctocol {
|
||||
</code></pre>
|
||||
<p>一个扩展可以扩展一个已有类型,使其能够适配一个或多个协议(protocol)。当这种情况发生时,协议的名字应该完全按照类或结构体的名字的方式进行书写:</p>
|
||||
<pre><code class="lang-swift">extension SomeType: SomeProtocol, AnotherProctocol {
|
||||
// 协议实现写到这里
|
||||
}
|
||||
</code></pre><p>按照这种方式添加的协议遵循者(protocol conformance)被称之为<a href="21_Protocols.html#adding_protocol_conformance_with_an_extension">在扩展中添加协议遵循者</a></p>
|
||||
</code></pre>
|
||||
<p>按照这种方式添加的协议遵循者(protocol conformance)被称之为<a href="21_Protocols.html#adding_protocol_conformance_with_an_extension">在扩展中添加协议遵循者</a></p>
|
||||
<p><a name="computed_properties"></a></p>
|
||||
<h2 id="-computed-properties-">计算型属性(Computed Properties)</h2>
|
||||
<p>扩展可以向已有类型添加计算型实例属性和计算型类型属性。下面的例子向 Swift 的内建<code>Double</code>类型添加了5个计算型实例属性,从而提供与距离单位协作的基本支持。</p>
|
||||
<pre><code>extension Double {
|
||||
<pre><code class="lang-swift">extension Double {
|
||||
var km: Double { return self * 1_000.0 }
|
||||
var m : Double { return self }
|
||||
var cm: Double { return self / 100.0 }
|
||||
@ -645,27 +645,27 @@ println("One inch is \(oneInch) meters")
|
||||
let threeFeet = 3.ft
|
||||
println("Three feet is \(threeFeet) meters")
|
||||
// 打印输出:"Three feet is 0.914399970739201 meters"
|
||||
</code></pre><p>这些计算属性表达的含义是把一个<code>Double</code>型的值看作是某单位下的长度值。即使它们被实现为计算型属性,但这些属性仍可以接一个带有dot语法的浮点型字面值,而这恰恰是使用这些浮点型字面量实现距离转换的方式。</p>
|
||||
</code></pre>
|
||||
<p>这些计算属性表达的含义是把一个<code>Double</code>型的值看作是某单位下的长度值。即使它们被实现为计算型属性,但这些属性仍可以接一个带有dot语法的浮点型字面值,而这恰恰是使用这些浮点型字面量实现距离转换的方式。</p>
|
||||
<p>在上述例子中,一个<code>Double</code>型的值<code>1.0</code>被用来表示“1米”。这就是为什么<code>m</code>计算型属性返回<code>self</code>——表达式<code>1.m</code>被认为是计算<code>1.0</code>的<code>Double</code>值。</p>
|
||||
<p>其它单位则需要一些转换来表示在米下测量的值。1千米等于1,000米,所以<code>km</code>计算型属性要把值乘以<code>1_000.00</code>来转化成单位米下的数值。类似地,1米有3.28024英尺,所以<code>ft</code>计算型属性要把对应的<code>Double</code>值除以<code>3.28024</code>来实现英尺到米的单位换算。</p>
|
||||
<p>这些属性是只读的计算型属性,所有从简考虑它们不用<code>get</code>关键字表示。它们的返回值是<code>Double</code>型,而且可以用于所有接受<code>Double</code>的数学计算中:</p>
|
||||
<pre><code>let aMarathon = 42.km + 195.m
|
||||
<pre><code class="lang-swift">let aMarathon = 42.km + 195.m
|
||||
println("A marathon is \(aMarathon) meters long")
|
||||
// 打印输出:"A marathon is 42495.0 meters long"
|
||||
</code></pre><blockquote>
|
||||
<p>注意:</p>
|
||||
<p>扩展可以添加新的计算属性,但是不可以添加存储属性,也不可以向已有属性添加属性观测器(property observers)。</p>
|
||||
</code></pre>
|
||||
<blockquote>
|
||||
<p>注意:<br>扩展可以添加新的计算属性,但是不可以添加存储属性,也不可以向已有属性添加属性观测器(property observers)。</p>
|
||||
</blockquote>
|
||||
<p><a name="initializers"></a></p>
|
||||
<h2 id="-initializers-">构造器(Initializers)</h2>
|
||||
<p>扩展可以向已有类型添加新的构造器。这可以让你扩展其它类型,将你自己的定制类型作为构造器参数,或者提供该类型的原始实现中没有包含的额外初始化选项。 </p>
|
||||
<p>扩展能向类中添加新的便利构造器,但是它们不能向类中添加新的指定构造器或析构函数。指定构造器和析构函数必须总是由原始的类实现来提供。</p>
|
||||
<blockquote>
|
||||
<p>注意:</p>
|
||||
<p>如果你使用扩展向一个值类型添加一个构造器,该构造器向所有的存储属性提供默认值,而且没有定义任何定制构造器(custom initializers),那么对于来自你的扩展构造器中的值类型,你可以调用默认构造器(default initializers)和逐一成员构造器(memberwise initializers)。<br>正如在值类型的构造器授权中描述的,如果你已经把构造器写成值类型原始实现的一部分,上述规则不再适用。</p>
|
||||
<p>注意:<br>如果你使用扩展向一个值类型添加一个构造器,该构造器向所有的存储属性提供默认值,而且没有定义任何定制构造器(custom initializers),那么对于来自你的扩展构造器中的值类型,你可以调用默认构造器(default initializers)和逐一成员构造器(memberwise initializers)。<br>正如在值类型的构造器授权中描述的,如果你已经把构造器写成值类型原始实现的一部分,上述规则不再适用。</p>
|
||||
</blockquote>
|
||||
<p>下面的例子定义了一个用于描述几何矩形的定制结构体<code>Rect</code>。这个例子同时定义了两个辅助结构体<code>Size</code>和<code>Point</code>,它们都把<code>0.0</code>作为所有属性的默认值:</p>
|
||||
<pre><code>struct Size {
|
||||
<pre><code class="lang-swift">struct Size {
|
||||
var width = 0.0, height = 0.0
|
||||
}
|
||||
struct Point {
|
||||
@ -675,56 +675,62 @@ struct Rect {
|
||||
var origin = Point()
|
||||
var size = Size()
|
||||
}
|
||||
</code></pre><p>因为结构体<code>Rect</code>提供了其所有属性的默认值,所以正如默认构造器中描述的,它可以自动接受一个默认的构造器和一个成员级构造器。这些构造器可以用于构造新的<code>Rect</code>实例:</p>
|
||||
<pre><code>let defaultRect = Rect()
|
||||
</code></pre>
|
||||
<p>因为结构体<code>Rect</code>提供了其所有属性的默认值,所以正如默认构造器中描述的,它可以自动接受一个默认的构造器和一个成员级构造器。这些构造器可以用于构造新的<code>Rect</code>实例:</p>
|
||||
<pre><code class="lang-swift">let defaultRect = Rect()
|
||||
let memberwiseRect = Rect(origin: Point(x: 2.0, y: 2.0),
|
||||
size: Size(width: 5.0, height: 5.0))
|
||||
</code></pre><p>你可以提供一个额外的使用特殊中心点和大小的构造器来扩展<code>Rect</code>结构体:</p>
|
||||
<pre><code>extension Rect {
|
||||
</code></pre>
|
||||
<p>你可以提供一个额外的使用特殊中心点和大小的构造器来扩展<code>Rect</code>结构体:</p>
|
||||
<pre><code class="lang-swift">extension Rect {
|
||||
init(center: Point, size: Size) {
|
||||
let originX = center.x - (size.width / 2)
|
||||
let originY = center.y - (size.height / 2)
|
||||
self.init(origin: Point(x: originX, y: originY), size: size)
|
||||
}
|
||||
}
|
||||
</code></pre><p>这个新的构造器首先根据提供的<code>center</code>和<code>size</code>值计算一个合适的原点。然后调用该结构体自动的成员构造器<code>init(origin:size:)</code>,该构造器将新的原点和大小存到了合适的属性中:</p>
|
||||
<pre><code>let centerRect = Rect(center: Point(x: 4.0, y: 4.0),
|
||||
</code></pre>
|
||||
<p>这个新的构造器首先根据提供的<code>center</code>和<code>size</code>值计算一个合适的原点。然后调用该结构体自动的成员构造器<code>init(origin:size:)</code>,该构造器将新的原点和大小存到了合适的属性中:</p>
|
||||
<pre><code class="lang-swift">let centerRect = Rect(center: Point(x: 4.0, y: 4.0),
|
||||
size: Size(width: 3.0, height: 3.0))
|
||||
// centerRect的原点是 (2.5, 2.5),大小是 (3.0, 3.0)
|
||||
</code></pre><blockquote>
|
||||
<p>注意:</p>
|
||||
<p>如果你使用扩展提供了一个新的构造器,你依旧有责任保证构造过程能够让所有实例完全初始化。</p>
|
||||
</code></pre>
|
||||
<blockquote>
|
||||
<p>注意:<br>如果你使用扩展提供了一个新的构造器,你依旧有责任保证构造过程能够让所有实例完全初始化。</p>
|
||||
</blockquote>
|
||||
<p><a name="methods"></a></p>
|
||||
<h2 id="-methods-">方法(Methods)</h2>
|
||||
<p>扩展可以向已有类型添加新的实例方法和类型方法。下面的例子向<code>Int</code>类型添加一个名为<code>repetitions</code>的新实例方法:</p>
|
||||
<pre><code>extension Int {
|
||||
<pre><code class="lang-swift">extension Int {
|
||||
func repetitions(task: () -> ()) {
|
||||
for i in 0..self {
|
||||
task()
|
||||
}
|
||||
}
|
||||
}
|
||||
</code></pre><p>这个<code>repetitions</code>方法使用了一个<code>() -> ()</code>类型的单参数(single argument),表明函数没有参数而且没有返回值。</p>
|
||||
</code></pre>
|
||||
<p>这个<code>repetitions</code>方法使用了一个<code>() -> ()</code>类型的单参数(single argument),表明函数没有参数而且没有返回值。</p>
|
||||
<p>定义该扩展之后,你就可以对任意整数调用<code>repetitions</code>方法,实现的功能则是多次执行某任务:</p>
|
||||
<pre><code>3.repetitions({
|
||||
<pre><code class="lang-swift">3.repetitions({
|
||||
println("Hello!")
|
||||
})
|
||||
// Hello!
|
||||
// Hello!
|
||||
// Hello!
|
||||
</code></pre><p>可以使用 trailing 闭包使调用更加简洁:</p>
|
||||
<pre><code>3.repetitions{
|
||||
</code></pre>
|
||||
<p>可以使用 trailing 闭包使调用更加简洁:</p>
|
||||
<pre><code class="lang-swift">3.repetitions{
|
||||
println("Goodbye!")
|
||||
}
|
||||
// Goodbye!
|
||||
// Goodbye!
|
||||
// Goodbye!
|
||||
</code></pre><p><a name="mutating_instance_methods"></a></p>
|
||||
</code></pre>
|
||||
<p><a name="mutating_instance_methods"></a></p>
|
||||
<h3 id="-mutating-instance-methods-">修改实例方法(Mutating Instance Methods)</h3>
|
||||
<p>通过扩展添加的实例方法也可以修改该实例本身。结构体和枚举类型中修改<code>self</code>或其属性的方法必须将该实例方法标注为<code>mutating</code>,正如来自原始实现的修改方法一样。</p>
|
||||
<p>下面的例子向Swift的<code>Int</code>类型添加了一个新的名为<code>square</code>的修改方法,来实现一个原始值的平方计算:</p>
|
||||
<pre><code>extension Int {
|
||||
<pre><code class="lang-swift">extension Int {
|
||||
mutating func square() {
|
||||
self = self * self
|
||||
}
|
||||
@ -732,7 +738,8 @@ let memberwiseRect = Rect(origin: Point(x: 2.0, y: 2.0),
|
||||
var someInt = 3
|
||||
someInt.square()
|
||||
// someInt 现在值是 9
|
||||
</code></pre><p><a name="subscripts"></a></p>
|
||||
</code></pre>
|
||||
<p><a name="subscripts"></a></p>
|
||||
<h2 id="-subscripts-">下标(Subscripts)</h2>
|
||||
<p>扩展可以向一个已有类型添加新下标。这个例子向Swift内建类型<code>Int</code>添加了一个整型下标。该下标<code>[n]</code>返回十进制数字从右向左数的第n个数字</p>
|
||||
<ul>
|
||||
@ -740,7 +747,7 @@ someInt.square()
|
||||
<li>123456789[1]返回8</li>
|
||||
</ul>
|
||||
<p>...等等</p>
|
||||
<pre><code>extension Int {
|
||||
<pre><code class="lang-swift">extension Int {
|
||||
subscript(digitIndex: Int) -> Int {
|
||||
var decimalBase = 1
|
||||
for _ in 1...digitIndex {
|
||||
@ -757,14 +764,16 @@ someInt.square()
|
||||
// returns 2
|
||||
746381295[8]
|
||||
// returns 7
|
||||
</code></pre><p>如果该<code>Int</code>值没有足够的位数,即下标越界,那么上述实现的下标会返回0,因为它会在数字左边自动补0:</p>
|
||||
<pre><code>746381295[9]
|
||||
</code></pre>
|
||||
<p>如果该<code>Int</code>值没有足够的位数,即下标越界,那么上述实现的下标会返回0,因为它会在数字左边自动补0:</p>
|
||||
<pre><code class="lang-swift">746381295[9]
|
||||
//returns 0, 即等同于:
|
||||
0746381295[9]
|
||||
</code></pre><p><a name="nested_types"></a></p>
|
||||
</code></pre>
|
||||
<p><a name="nested_types"></a></p>
|
||||
<h2 id="-nested-types-">嵌套类型(Nested Types)</h2>
|
||||
<p>扩展可以向已有的类、结构体和枚举添加新的嵌套类型:</p>
|
||||
<pre><code>extension Character {
|
||||
<pre><code class="lang-swift">extension Character {
|
||||
enum Kind {
|
||||
case Vowel, Consonant, Other
|
||||
}
|
||||
@ -780,10 +789,11 @@ someInt.square()
|
||||
}
|
||||
}
|
||||
}
|
||||
</code></pre><p>该例子向<code>Character</code>添加了新的嵌套枚举。这个名为<code>Kind</code>的枚举表示特定字符的类型。具体来说,就是表示一个标准的拉丁脚本中的字符是元音还是辅音(不考虑口语和地方变种),或者是其它类型。</p>
|
||||
</code></pre>
|
||||
<p>该例子向<code>Character</code>添加了新的嵌套枚举。这个名为<code>Kind</code>的枚举表示特定字符的类型。具体来说,就是表示一个标准的拉丁脚本中的字符是元音还是辅音(不考虑口语和地方变种),或者是其它类型。</p>
|
||||
<p>这个类子还向<code>Character</code>添加了一个新的计算实例属性,即<code>kind</code>,用来返回合适的<code>Kind</code>枚举成员。</p>
|
||||
<p>现在,这个嵌套枚举可以和一个<code>Character</code>值联合使用了:</p>
|
||||
<pre><code>func printLetterKinds(word: String) {
|
||||
<pre><code class="lang-swift">func printLetterKinds(word: String) {
|
||||
println("'\\(word)' is made up of the following kinds of letters:")
|
||||
for character in word {
|
||||
switch character.kind {
|
||||
@ -800,10 +810,10 @@ someInt.square()
|
||||
printLetterKinds("Hello")
|
||||
// 'Hello' is made up of the following kinds of letters:
|
||||
// consonant vowel consonant consonant vowel
|
||||
</code></pre><p>函数<code>printLetterKinds</code>的输入是一个<code>String</code>值并对其字符进行迭代。在每次迭代过程中,考虑当前字符的<code>kind</code>计算属性,并打印出合适的类别描述。所以<code>printLetterKinds</code>就可以用来打印一个完整单词中所有字母的类型,正如上述单词<code>"hello"</code>所展示的。</p>
|
||||
</code></pre>
|
||||
<p>函数<code>printLetterKinds</code>的输入是一个<code>String</code>值并对其字符进行迭代。在每次迭代过程中,考虑当前字符的<code>kind</code>计算属性,并打印出合适的类别描述。所以<code>printLetterKinds</code>就可以用来打印一个完整单词中所有字母的类型,正如上述单词<code>"hello"</code>所展示的。</p>
|
||||
<blockquote>
|
||||
<p>注意:</p>
|
||||
<p>由于已知<code>character.kind</code>是<code>Character.Kind</code>型,所以<code>Character.Kind</code>中的所有成员值都可以使用<code>switch</code>语句里的形式简写,比如使用 <code>.Vowel</code>代替<code>Character.Kind.Vowel</code></p>
|
||||
<p>注意:<br>由于已知<code>character.kind</code>是<code>Character.Kind</code>型,所以<code>Character.Kind</code>中的所有成员值都可以使用<code>switch</code>语句里的形式简写,比如使用 <code>.Vowel</code>代替<code>Character.Kind.Vowel</code></p>
|
||||
</blockquote>
|
||||
|
||||
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="2.21" data-basepath=".." data-revision="1402750255397">
|
||||
<div class="book" data-level="2.21" data-basepath=".." data-revision="1402759431779">
|
||||
<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,11 +587,11 @@
|
||||
|
||||
<div class="page-inner">
|
||||
|
||||
<section class="normal" id="section-gitbook_74">
|
||||
<section class="normal" id="section-gitbook_550">
|
||||
|
||||
<blockquote>
|
||||
<p>翻译:geek5nan</p>
|
||||
<p>校对:dabing1022</p>
|
||||
<p>翻译:geek5nan
|
||||
校对:dabing1022</p>
|
||||
</blockquote>
|
||||
<h1 id="-">协议</h1>
|
||||
<hr>
|
||||
@ -604,7 +604,7 @@
|
||||
<li><a href="#protocols_as_types">协议类型(Protocols as Types)</a></li>
|
||||
<li><a href="#delegation">委托(代理)模式(Delegation)</a></li>
|
||||
<li><a href="#adding_protocol_conformance_with_an_extension">在扩展中添加协议成员(Adding Protocol Conformance with an Extension)</a></li>
|
||||
<li><a href="#declaring_protocol_adoption_with_an_extension">通过延展补充协议声明(Declaring Protocol Adoption with an Extension)</a></li>
|
||||
<li><a href="#declaring_protocol_adoption_with_an_extension">通过扩展补充协议声明(Declaring Protocol Adoption with an Extension)</a></li>
|
||||
<li><a href="#collections_of_protocol_types">集合中的协议类型(Collections of Protocol Types)</a></li>
|
||||
<li><a href="#protocol_inheritance">协议的继承(Protocol Inheritance)</a></li>
|
||||
<li><a href="#protocol_composition">协议合成(Protocol Composition)</a></li>
|
||||
@ -616,42 +616,49 @@
|
||||
<p><a name="protocol_syntax"></a></p>
|
||||
<h2 id="-">协议的语法</h2>
|
||||
<p><code>协议</code>的定义与类,结构体,枚举的定义非常相似,如下所示:</p>
|
||||
<pre><code>protocol SomeProtocol {
|
||||
<pre><code class="lang-swift">protocol SomeProtocol {
|
||||
// 协议内容
|
||||
}
|
||||
</code></pre><p>在类,结构体,枚举的名称后加上<code>协议名称</code>,中间以冒号<code>:</code>分隔即可实现协议;实现多个协议时,各协议之间用逗号<code>,</code>分隔,如下所示:</p>
|
||||
<pre><code>struct SomeStructure: FirstProtocol, AnotherProtocol {
|
||||
</code></pre>
|
||||
<p>在类,结构体,枚举的名称后加上<code>协议名称</code>,中间以冒号<code>:</code>分隔即可实现协议;实现多个协议时,各协议之间用逗号<code>,</code>分隔,如下所示:</p>
|
||||
<pre><code class="lang-swift">struct SomeStructure: FirstProtocol, AnotherProtocol {
|
||||
// 结构体内容
|
||||
}
|
||||
</code></pre><p>当某个类含有父类的同时并实现了协议,应当把父类放在所有的协议之前,如下所示:</p>
|
||||
<pre><code>class SomeClass: SomeSuperClass, FirstProtocol, AnotherProtocol {
|
||||
</code></pre>
|
||||
<p>当某个类含有父类的同时并实现了协议,应当把父类放在所有的协议之前,如下所示:</p>
|
||||
<pre><code class="lang-swift">class SomeClass: SomeSuperClass, FirstProtocol, AnotherProtocol {
|
||||
// 类的内容
|
||||
}
|
||||
</code></pre><p><a name="property_requirements"></a></p>
|
||||
</code></pre>
|
||||
<p><a name="property_requirements"></a></p>
|
||||
<h2 id="-">属性要求</h2>
|
||||
<p><code>协议</code>能够要求其<code>遵循者</code>必须含有一些<strong>特定名称和类型</strong>的<code>实例属性(instance property)</code>或<code>类属性 (type property)</code>,也能够要求属性的<code>(设置权限)settable</code> 和<code>(访问权限)gettable</code>,但它不要求<code>属性</code>是<code>存储型属性(stored property)</code>还是<code>计算型属性(calculate property)</code>。</p>
|
||||
<p><code>协议</code>能够要求其<code>遵循者</code>必须含有一些<strong>特定名称和类型</strong>的<code>实例属性(instance property)</code>或<code>类属性 (type property)</code>,也能够要求属性具有<code>(设置权限)settable</code> 和<code>(访问权限)gettable</code>,但它不要求<code>属性</code>是<code>存储型属性(stored property)</code>还是<code>计算型属性(calculate property)</code>。</p>
|
||||
<p>如果协议要求属性具有设置权限和访问权限,那常量存储型属性或者只读计算型属性都无法满足此要求。如果协议只要求属性具有访问权限,那任何类型的属性都可以满足此要求,无论这些属性是否具有设置权限。</p>
|
||||
<p>通常前置<code>var</code>关键字将属性声明为变量。在属性声明后写上<code>{ get set }</code>表示属性为可读写的。<code>{ get }</code>用来表示属性为可读的。即使你为可读的属性实现了<code>setter</code>方法,它也不会出错。</p>
|
||||
<pre><code>protocol SomeProtocol {
|
||||
<pre><code class="lang-swift">protocol SomeProtocol {
|
||||
var musBeSettable : Int { get set }
|
||||
var doesNotNeedToBeSettable: Int { get }
|
||||
}
|
||||
</code></pre><p>用类来实现协议时,使用<code>class</code>关键字来表示该属性为类成员;用结构体或枚举实现协议时,则使用<code>static</code>关键字来表示:</p>
|
||||
<pre><code>protocol AnotherProtocol {
|
||||
</code></pre>
|
||||
<p>用类来实现协议时,使用<code>class</code>关键字来表示该属性为类成员;用结构体或枚举实现协议时,则使用<code>static</code>关键字来表示:</p>
|
||||
<pre><code class="lang-swift">protocol AnotherProtocol {
|
||||
class var someTypeProperty: Int { get set }
|
||||
}
|
||||
|
||||
protocol FullyNamed {
|
||||
var fullName: String { get }
|
||||
}
|
||||
</code></pre><p><code>FullyNamed</code>协议含有<code>fullName</code>属性。因此其<code>遵循者</code>必须含有一个名为<code>fullName</code>,类型为<code>String</code>的可读属性。</p>
|
||||
<pre><code>struct Person: FullyNamed{
|
||||
</code></pre>
|
||||
<p><code>FullyNamed</code>协议含有<code>fullName</code>属性。因此其<code>遵循者</code>必须含有一个名为<code>fullName</code>,类型为<code>String</code>的可读属性。</p>
|
||||
<pre><code class="lang-swift">struct Person: FullyNamed{
|
||||
var fullName: String
|
||||
}
|
||||
let john = Person(fullName: "John Appleseed")
|
||||
//john.fullName 为 "John Appleseed"
|
||||
</code></pre><p><code>Person</code>结构体含有一个名为<code>fullName</code>的<code>存储型属性</code>,完整的<code>遵循</code>了协议。(<em>若协议未被完整遵循,编译时则会报错</em>)。</p>
|
||||
</code></pre>
|
||||
<p><code>Person</code>结构体含有一个名为<code>fullName</code>的<code>存储型属性</code>,完整的<code>遵循</code>了协议。(<em>若协议未被完整遵循,编译时则会报错</em>)。</p>
|
||||
<p>如下所示,<code>Startship</code>类<code>遵循</code>了<code>FullyNamed</code>协议:</p>
|
||||
<pre><code>class Starship: FullyNamed {
|
||||
<pre><code class="lang-swift">class Starship: FullyNamed {
|
||||
var prefix: String?
|
||||
var name: String
|
||||
init(name: String, prefix: String? = nil ) {
|
||||
@ -664,25 +671,27 @@ let john = Person(fullName: "John Appleseed")
|
||||
}
|
||||
var ncc1701 = Starship(name: "Enterprise", prefix: "USS")
|
||||
// ncc1701.fullName == "USS Enterprise"
|
||||
</code></pre><p><code>Starship</code>类将<code>fullName</code>实现为可读的<code>计算型属性</code>。它的每一个实例都有一个名为<code>name</code>的必备属性和一个名为<code>prefix</code>的可选属性。 当<code>prefix</code>存在时,将<code>prefix</code>插入到<code>name</code>之前来为<code>Starship</code>构建<code>fullName</code>。</p>
|
||||
</code></pre>
|
||||
<p><code>Starship</code>类将<code>fullName</code>实现为可读的<code>计算型属性</code>。它的每一个实例都有一个名为<code>name</code>的必备属性和一个名为<code>prefix</code>的可选属性。 当<code>prefix</code>存在时,将<code>prefix</code>插入到<code>name</code>之前来为<code>Starship</code>构建<code>fullName</code>。</p>
|
||||
<p><a name="method_requirements"></a></p>
|
||||
<h2 id="-">方法要求</h2>
|
||||
<p><code>协议</code>能够要求其<code>遵循者</code>必备某些特定的<code>实例方法</code>和<code>类方法</code>。协议方法的声明与普通方法声明相似,但它不需要<code>方法</code>内容。</p>
|
||||
<blockquote>
|
||||
<p>注意:</p>
|
||||
<p>协议方法支持<code>变长参数(variadic parameter)</code>,不支持<code>默认参数(default parameter)</code>。</p>
|
||||
<p>注意:
|
||||
协议方法支持<code>变长参数(variadic parameter)</code>,不支持<code>默认参数(default parameter)</code>。</p>
|
||||
</blockquote>
|
||||
<p>前置<code>class</code>关键字表示协议中的成员为<code>类成员</code>;当协议用于被<code>枚举</code>或<code>结构体</code>遵循时,则使用<code>static</code>关键字。如下所示:</p>
|
||||
<pre><code>protocol SomeProtocol {
|
||||
<pre><code class="lang-swift">protocol SomeProtocol {
|
||||
class func someTypeMethod()
|
||||
}
|
||||
|
||||
protocol RandomNumberGenerator {
|
||||
func random() -> Double
|
||||
}
|
||||
</code></pre><p><code>RandomNumberGenerator</code>协议要求其<code>遵循者</code>必须拥有一个名为<code>random</code>, 返回值类型为<code>Double</code>的实例方法。(我们假设随机数在[0,1]区间内)。</p>
|
||||
</code></pre>
|
||||
<p><code>RandomNumberGenerator</code>协议要求其<code>遵循者</code>必须拥有一个名为<code>random</code>, 返回值类型为<code>Double</code>的实例方法。(我们假设随机数在[0,1]区间内)。</p>
|
||||
<p><code>LinearCongruentialGenerator</code>类<code>遵循</code>了<code>RandomNumberGenerator</code>协议,并提供了一个叫做<em>线性同余生成器(linear congruential generator)</em>的伪随机数算法。</p>
|
||||
<pre><code>class LinearCongruentialGenerator: RandomNumberGenerator {
|
||||
<pre><code class="lang-swift">class LinearCongruentialGenerator: RandomNumberGenerator {
|
||||
var lastRandom = 42.0
|
||||
let m = 139968.0
|
||||
let a = 3877.0
|
||||
@ -697,21 +706,23 @@ println("Here's a random number: \(generator.random())")
|
||||
// 输出 : "Here's a random number: 0.37464991998171"
|
||||
println("And another one: \(generator.random())")
|
||||
// 输出 : "And another one: 0.729023776863283"
|
||||
</code></pre><p><a name="mutating_method_requirements"></a></p>
|
||||
</code></pre>
|
||||
<p><a name="mutating_method_requirements"></a></p>
|
||||
<h2 id="-">突变方法要求</h2>
|
||||
<p>能在<code>方法</code>或<code>函数</code>内部改变实例类型的方法称为<code>突变方法</code>。在<code>值类型(Value Type)</code>(<em>译者注:特指结构体和枚举</em>)中的的<code>函数</code>前缀加上<code>mutating</code>关键字来表示该函数允许改变该实例和其属性的类型。 这一变换过程在<a href="11_Methods.html#instance_methods">实例方法(Instance Methods)</a>章节中有详细描述。</p>
|
||||
<p>(<em>译者注:类中的成员为<code>引用类型(Reference Type)</code>,可以方便的修改实例及其属性的值而无需改变类型;而<code>结构体</code>和<code>枚举</code>中的成员均为<code>值类型(Value Type)</code>,修改变量的值就相当于修改变量的类型,而<code>Swift</code>默认不允许修改类型,因此需要前置<code>mutating</code>关键字用来表示该<code>函数</code>中能够修改类型</em>)</p>
|
||||
<blockquote>
|
||||
<p>注意:</p>
|
||||
<p>用<code>class</code>实现协议中的<code>mutating</code>方法时,不用写<code>mutating</code>关键字;用<code>结构体</code>,<code>枚举</code>实现协议中的<code>mutating</code>方法时,必须写<code>mutating</code>关键字。</p>
|
||||
<p>注意:
|
||||
用<code>class</code>实现协议中的<code>mutating</code>方法时,不用写<code>mutating</code>关键字;用<code>结构体</code>,<code>枚举</code>实现协议中的<code>mutating</code>方法时,必须写<code>mutating</code>关键字。</p>
|
||||
</blockquote>
|
||||
<p>如下所示,<code>Togglable</code>协议含有<code>toggle</code>函数。根据函数名称推测,<code>toggle</code>可能用于<strong>切换或恢复</strong>某个属性的状态。<code>mutating</code>关键字表示它为<code>突变方法</code>:</p>
|
||||
<pre><code>protocol Togglable {
|
||||
<pre><code class="lang-swift">protocol Togglable {
|
||||
mutating func toggle()
|
||||
}
|
||||
</code></pre><p>当使用<code>枚举</code>或<code>结构体</code>来实现<code>Togglabl</code>协议时,必须在<code>toggle</code>方法前加上<code>mutating</code>关键字。</p>
|
||||
</code></pre>
|
||||
<p>当使用<code>枚举</code>或<code>结构体</code>来实现<code>Togglabl</code>协议时,必须在<code>toggle</code>方法前加上<code>mutating</code>关键字。</p>
|
||||
<p>如下所示,<code>OnOffSwitch</code>枚举<code>遵循</code>了<code>Togglable</code>协议,<code>On</code>,<code>Off</code>两个成员用于表示当前状态</p>
|
||||
<pre><code>enum OnOffSwitch: Togglable {
|
||||
<pre><code class="lang-swift">enum OnOffSwitch: Togglable {
|
||||
case Off, On
|
||||
mutating func toggle() {
|
||||
switch self {
|
||||
@ -725,7 +736,8 @@ println("And another one: \(generator.random())")
|
||||
var lightSwitch = OnOffSwitch.Off
|
||||
lightSwitch.toggle()
|
||||
//lightSwitch 现在的值为 .On
|
||||
</code></pre><p><a name="protocols_as_types"></a></p>
|
||||
</code></pre>
|
||||
<p><a name="protocols_as_types"></a></p>
|
||||
<h2 id="-">协议类型</h2>
|
||||
<p><code>协议</code>本身不实现任何功能,但你可以将它当做<code>类型</code>来使用。</p>
|
||||
<p>使用场景:</p>
|
||||
@ -735,10 +747,10 @@ lightSwitch.toggle()
|
||||
<li>作为数组,字典或其他容器中的元素类型</li>
|
||||
</ul>
|
||||
<blockquote>
|
||||
<p>注意:</p>
|
||||
<p>协议类型应与其他类型(Int,Double,String)的写法相同,使用驼峰式</p>
|
||||
<p>注意:
|
||||
协议类型应与其他类型(Int,Double,String)的写法相同,使用驼峰式</p>
|
||||
</blockquote>
|
||||
<pre><code>class Dice {
|
||||
<pre><code class="lang-swift">class Dice {
|
||||
let sides: Int
|
||||
let generator: RandomNumberGenerator
|
||||
init(sides: Int, generator: RandomNumberGenerator) {
|
||||
@ -749,12 +761,13 @@ lightSwitch.toggle()
|
||||
return Int(generator.random() * Double(sides)) +1
|
||||
}
|
||||
}
|
||||
</code></pre><p>这里定义了一个名为 <code>Dice</code>的类,用来代表桌游中的N个面的骰子。</p>
|
||||
<p> <code>Dice</code>含有<code>sides</code>和<code>generator</code>两个属性,前者用来表示骰子有几个面,后者为骰子提供一个随机数生成器。由于后者为<code>RandomNumberGenerator</code>的协议类型。所以它能够被赋值为任意<code>遵循</code>该协议的类型。</p>
|
||||
</code></pre>
|
||||
<p>这里定义了一个名为 <code>Dice</code>的类,用来代表桌游中的N个面的骰子。</p>
|
||||
<p><code>Dice</code>含有<code>sides</code>和<code>generator</code>两个属性,前者用来表示骰子有几个面,后者为骰子提供一个随机数生成器。由于后者为<code>RandomNumberGenerator</code>的协议类型。所以它能够被赋值为任意<code>遵循</code>该协议的类型。</p>
|
||||
<p>此外,使用<code>构造器(init)</code>来代替之前版本中的<code>setup</code>操作。构造器中含有一个名为<code>generator</code>,类型为<code>RandomNumberGenerator</code>的形参,使得它可以接收任意遵循<code>RandomNumberGenerator</code>协议的类型。</p>
|
||||
<p><code>roll</code>方法用来模拟骰子的面值。它先使用<code>generator</code>的<code>random</code>方法来创建一个[0-1]区间内的随机数种子,然后加工这个随机数种子生成骰子的面值。</p>
|
||||
<p>如下所示,<code>LinearCongruentialGenerator</code>的实例作为随机数生成器传入<code>Dice</code>的<code>构造器</code></p>
|
||||
<pre><code>var d6 = Dice(sides: 6,generator: LinearCongruentialGenerator())
|
||||
<pre><code class="lang-swift">var d6 = Dice(sides: 6,generator: LinearCongruentialGenerator())
|
||||
for _ in 1...5 {
|
||||
println("Random dice roll is \(d6.roll())")
|
||||
}
|
||||
@ -764,24 +777,27 @@ for _ in 1...5 {
|
||||
//Random dice roll is 4
|
||||
//Random dice roll is 5
|
||||
//Random dice roll is 4
|
||||
</code></pre><p><a name="delegation"></a></p>
|
||||
</code></pre>
|
||||
<p><a name="delegation"></a></p>
|
||||
<h2 id="-">委托(代理)模式</h2>
|
||||
<p>委托是一种设计模式,它允许类或结构体将一些需要它们负责的功能<code>交由(委托)</code>给其他的类型。</p>
|
||||
<p>委托模式的实现很简单: 定义<code>协议</code>来<code>封装</code>那些需要被委托的<code>函数和方法</code>, 使其<code>遵循者</code>拥有这些被委托的<code>函数和方法</code>。</p>
|
||||
<p>委托模式可以用来响应特定的动作或接收外部数据源提供的数据,而无需要知道外部数据源的类型。</p>
|
||||
<p>下文是两个基于骰子游戏的协议:</p>
|
||||
<pre><code>protocol DiceGame {
|
||||
<pre><code class="lang-swift">protocol DiceGame {
|
||||
var dice: Dice { get }
|
||||
func play()
|
||||
}
|
||||
|
||||
protocol DiceGameDelegate {
|
||||
func gameDidStart(game: DiceGame)
|
||||
func game(game: DiceGame, didStartNewTurnWithDiceRoll diceRoll:Int)
|
||||
func gameDidEnd(game: DiceGame)
|
||||
}
|
||||
</code></pre><p><code>DiceGame</code>协议可以在任意含有骰子的游戏中实现,<code>DiceGameDelegate</code>协议可以用来追踪<code>DiceGame</code>的游戏过程。</p>
|
||||
</code></pre>
|
||||
<p><code>DiceGame</code>协议可以在任意含有骰子的游戏中实现,<code>DiceGameDelegate</code>协议可以用来追踪<code>DiceGame</code>的游戏过程。</p>
|
||||
<p>如下所示,<code>SnakesAndLadders</code>是<code>Snakes and Ladders</code>(译者注:<a href="05_Control_Flow.html">控制流</a>章节有该游戏的详细介绍)游戏的新版本。新版本使用<code>Dice</code>作为骰子,并且实现了<code>DiceGame</code>和<code>DiceGameDelegate</code>协议</p>
|
||||
<pre><code>class SnakesAndLadders: DiceGame {
|
||||
<pre><code class="lang-swift">class SnakesAndLadders: DiceGame {
|
||||
let finalSquare = 25
|
||||
let dic = Dice(sides: 6, generator: LinearCongruentialGenerator())
|
||||
var square = 0
|
||||
@ -811,15 +827,16 @@ protocol DiceGameDelegate {
|
||||
delegate?.gameDIdEnd(self)
|
||||
}
|
||||
}
|
||||
</code></pre><p>游戏的<code>初始化设置(setup)</code>被<code>SnakesAndLadders</code>类的<code>构造器(initializer)</code>实现。所有的游戏逻辑被转移到了<code>play</code>方法中。</p>
|
||||
</code></pre>
|
||||
<p>游戏的<code>初始化设置(setup)</code>被<code>SnakesAndLadders</code>类的<code>构造器(initializer)</code>实现。所有的游戏逻辑被转移到了<code>play</code>方法中。</p>
|
||||
<blockquote>
|
||||
<p>注意:</p>
|
||||
<p>因为<code>delegate</code>并不是该游戏的必备条件,<code>delegate</code>被定义为遵循<code>DiceGameDelegate</code>协议的可选属性</p>
|
||||
<p>注意:
|
||||
因为<code>delegate</code>并不是该游戏的必备条件,<code>delegate</code>被定义为遵循<code>DiceGameDelegate</code>协议的可选属性</p>
|
||||
</blockquote>
|
||||
<p><code>DicegameDelegate</code>协议提供了三个方法用来追踪游戏过程。被放置于游戏的逻辑中,即<code>play()</code>方法内。分别在游戏开始时,新一轮开始时,游戏结束时被调用。</p>
|
||||
<p>因为<code>delegate</code>是一个遵循<code>DiceGameDelegate</code>的可选属性,因此在<code>play()</code>方法中使用了<code>可选链</code>来调用委托方法。 若<code>delegate</code>属性为<code>nil</code>, 则委托调用<em>优雅地</em>失效。若<code>delegate</code>不为<code>nil</code>,则委托方法被调用</p>
|
||||
<p>如下所示,<code>DiceGameTracker</code>遵循了<code>DiceGameDelegate</code>协议</p>
|
||||
<pre><code>class DiceGameTracker: DiceGameDelegate {
|
||||
<pre><code class="lang-swift">class DiceGameTracker: DiceGameDelegate {
|
||||
var numberOfTurns = 0
|
||||
func gameDidStart(game: DiceGame) {
|
||||
numberOfTurns = 0
|
||||
@ -836,10 +853,11 @@ protocol DiceGameDelegate {
|
||||
println("The game lasted for \(numberOfTurns) turns")
|
||||
}
|
||||
}
|
||||
</code></pre><p><code>DiceGameTracker</code>实现了<code>DiceGameDelegate</code>协议的方法要求,用来记录游戏已经进行的轮数。 当游戏开始时,<code>numberOfTurns</code>属性被赋值为0;在每新一轮中递加;游戏结束后,输出打印游戏的总轮数。</p>
|
||||
</code></pre>
|
||||
<p><code>DiceGameTracker</code>实现了<code>DiceGameDelegate</code>协议的方法要求,用来记录游戏已经进行的轮数。 当游戏开始时,<code>numberOfTurns</code>属性被赋值为0;在每新一轮中递加;游戏结束后,输出打印游戏的总轮数。</p>
|
||||
<p><code>gameDidStart</code>方法从<code>game</code>参数获取游戏信息并输出。<code>game</code>在方法中被当做<code>DiceGame</code>类型而不是<code>SnakeAndLadders</code>类型,所以方法中只能访问<code>DiceGame</code>协议中的成员。</p>
|
||||
<p><code>DiceGameTracker</code>的运行情况,如下所示:</p>
|
||||
<pre><code>“let tracker = DiceGameTracker()
|
||||
<pre><code class="lang-swift">let tracker = DiceGameTracker()
|
||||
let game = SnakesAndLadders()
|
||||
game.delegate = tracker
|
||||
game.play()
|
||||
@ -849,80 +867,91 @@ game.play()
|
||||
// Rolled a 5
|
||||
// Rolled a 4
|
||||
// Rolled a 5
|
||||
// The game lasted for 4 turns”
|
||||
</code></pre><p><a name="adding_protocol_conformance_with_an_extension"></a></p>
|
||||
// The game lasted for 4 turns
|
||||
</code></pre>
|
||||
<p><a name="adding_protocol_conformance_with_an_extension"></a></p>
|
||||
<h2 id="-">在扩展中添加协议成员</h2>
|
||||
<p>即便无法修改源代码,依然可以通过<code>扩展(Extension)</code>来扩充已存在类型(<em>译者注: 类,结构体,枚举等</em>)。<code>扩展</code>可以为已存在的类型添加<code>属性</code>,<code>方法</code>,<code>下标</code>,<code>协议</code>等成员。详情请在<a href="20_Extensions.html">扩展</a>章节中查看。</p>
|
||||
<blockquote>
|
||||
<p>注意:</p>
|
||||
<p>通过<code>扩展</code>为已存在的类型<code>遵循</code>协议时,该类型的所有实例也会随之添加协议中的方法</p>
|
||||
<p>注意:
|
||||
通过<code>扩展</code>为已存在的类型<code>遵循</code>协议时,该类型的所有实例也会随之添加协议中的方法</p>
|
||||
</blockquote>
|
||||
<p><code>TextRepresentable</code>协议含有一个<code>asText</code>,如下所示:</p>
|
||||
<pre><code>protocol TextRepresentable {
|
||||
<pre><code class="lang-swift">protocol TextRepresentable {
|
||||
func asText() -> String
|
||||
}
|
||||
</code></pre><p>通过<code>扩展</code>为上一节中提到的<code>Dice</code>类遵循<code>TextRepresentable</code>协议</p>
|
||||
<pre><code>extension Dice: TextRepresentable {
|
||||
func asText() -> String {
|
||||
</code></pre>
|
||||
<p>通过<code>扩展</code>为上一节中提到的<code>Dice</code>类遵循<code>TextRepresentable</code>协议</p>
|
||||
<pre><code class="lang-swift">extension Dice: TextRepresentable {
|
||||
cun asText() -> String {
|
||||
return "A \(sides)-sided dice"
|
||||
}
|
||||
}
|
||||
</code></pre><p>从现在起,<code>Dice</code>类型的实例可被当作<code>TextRepresentable</code>类型:</p>
|
||||
<pre><code>let d12 = Dice(sides: 12,generator: LinearCongruentialGenerator())
|
||||
</code></pre>
|
||||
<p>从现在起,<code>Dice</code>类型的实例可被当作<code>TextRepresentable</code>类型:</p>
|
||||
<pre><code class="lang-swift">let d12 = Dice(sides: 12,generator: LinearCongruentialGenerator())
|
||||
println(d12.asText())
|
||||
// 输出 "A 12-sided dice"
|
||||
</code></pre><p><code>SnakesAndLadders</code>类也可以通过<code>扩展</code>的方式来遵循协议:</p>
|
||||
<pre><code>extension SnakeAndLadders: TextRepresentable {
|
||||
</code></pre>
|
||||
<p><code>SnakesAndLadders</code>类也可以通过<code>扩展</code>的方式来遵循协议:</p>
|
||||
<pre><code class="lang-swift">extension SnakeAndLadders: TextRepresentable {
|
||||
func asText() -> String {
|
||||
return "A game of Snakes and Ladders with \(finalSquare) squares"
|
||||
}
|
||||
}
|
||||
println(game.asText())
|
||||
// 输出 "A game of Snakes and Ladders with 25 squares"
|
||||
</code></pre><p><a name="declaring_protocol_adoption_with_an_extension"></a></p>
|
||||
<h2 id="-">通过延展补充协议声明</h2>
|
||||
</code></pre>
|
||||
<p><a name="declaring_protocol_adoption_with_an_extension"></a></p>
|
||||
<h2 id="-">通过扩展补充协议声明</h2>
|
||||
<p>当一个类型已经实现了协议中的所有要求,却没有声明时,可以通过<code>扩展</code>来补充协议声明:</p>
|
||||
<pre><code>struct Hamster {
|
||||
<pre><code class="lang-swift">struct Hamster {
|
||||
var name: String
|
||||
func asText() -> String {
|
||||
return "A hamster named \(name)"
|
||||
}
|
||||
}
|
||||
extension Hamster: TextRepresentabl {}
|
||||
</code></pre><p>从现在起,<code>Hamster</code>的实例可以作为<code>TextRepresentable</code>类型使用</p>
|
||||
<pre><code>let simonTheHamster = Hamster(name: "Simon")
|
||||
</code></pre>
|
||||
<p>从现在起,<code>Hamster</code>的实例可以作为<code>TextRepresentable</code>类型使用</p>
|
||||
<pre><code class="lang-swift">let simonTheHamster = Hamster(name: "Simon")
|
||||
let somethingTextRepresentable: TextRepresentabl = simonTheHamester
|
||||
println(somethingTextRepresentable.asText())
|
||||
// 输出 "A hamster named Simon"
|
||||
</code></pre><blockquote>
|
||||
<p>注意:</p>
|
||||
<p>即时满足了协议的所有要求,类型也不会自动转变,因此你必须为它做出明显的协议声明</p>
|
||||
</code></pre>
|
||||
<blockquote>
|
||||
<p>注意:
|
||||
即时满足了协议的所有要求,类型也不会自动转变,因此你必须为它做出明显的协议声明</p>
|
||||
</blockquote>
|
||||
<p><a name="collections_of_protocol_types"></a></p>
|
||||
<h2 id="-">集合中的协议类型</h2>
|
||||
<p>协议类型可以被集合使用,表示集合中的元素均为协议类型:</p>
|
||||
<pre><code>let things: TextRepresentable[] = [game,d12,simoTheHamster]
|
||||
</code></pre><p>如下所示,<code>things</code>数组可以被直接遍历,并调用其中元素的<code>asText()</code>函数:</p>
|
||||
<pre><code>for thing in things {
|
||||
<pre><code class="lang-swift">let things: TextRepresentable[] = [game,d12,simoTheHamster]
|
||||
</code></pre>
|
||||
<p>如下所示,<code>things</code>数组可以被直接遍历,并调用其中元素的<code>asText()</code>函数:</p>
|
||||
<pre><code class="lang-swift">for thing in things {
|
||||
println(thing.asText())
|
||||
}
|
||||
// A game of Snakes and Ladders with 25 squares
|
||||
// A 12-sided dice
|
||||
// A hamster named Simon
|
||||
</code></pre><p><code>thing</code>被当做是<code>TextRepresentable</code>类型而不是<code>Dice</code>,<code>DiceGame</code>,<code>Hamster</code>等类型。因此能且仅能调用<code>asText</code>方法</p>
|
||||
</code></pre>
|
||||
<p><code>thing</code>被当做是<code>TextRepresentable</code>类型而不是<code>Dice</code>,<code>DiceGame</code>,<code>Hamster</code>等类型。因此能且仅能调用<code>asText</code>方法</p>
|
||||
<p><a name="protocol_inheritance"></a></p>
|
||||
<h2 id="-">协议的继承</h2>
|
||||
<p>协议能够<em>继承</em>一到多个其他协议。语法与类的继承相似,多个协议间用逗号<code>,</code>分隔</p>
|
||||
<pre><code>protocol InheritingProtocol: SomeProtocol, AnotherProtocol {
|
||||
<pre><code class="lang-swift">protocol InheritingProtocol: SomeProtocol, AnotherProtocol {
|
||||
// 协议定义
|
||||
}
|
||||
</code></pre><p>如下所示,<code>PrettyTextRepresentable</code>协议继承了<code>TextRepresentable</code>协议</p>
|
||||
<pre><code>protocol PrettyTextRepresentable: TextRepresentable {
|
||||
</code></pre>
|
||||
<p>如下所示,<code>PrettyTextRepresentable</code>协议继承了<code>TextRepresentable</code>协议</p>
|
||||
<pre><code class="lang-swift">protocol PrettyTextRepresentable: TextRepresentable {
|
||||
func asPrettyText() -> String
|
||||
}
|
||||
</code></pre><p><code>遵循``PrettyTextRepresentable</code>协议的同时,也需要<code>遵循</code>TextRepresentable`协议。</p>
|
||||
</code></pre>
|
||||
<p><code>遵循``PrettyTextRepresentable</code>协议的同时,也需要<code>遵循</code>TextRepresentable`协议。</p>
|
||||
<p>如下所示,用<code>扩展</code>为<code>SnakesAndLadders</code>遵循<code>PrettyTextRepresentable</code>协议:</p>
|
||||
<pre><code>extension SnakesAndLadders: PrettyTextRepresentable {
|
||||
<pre><code class="lang-swift">extension SnakesAndLadders: PrettyTextRepresentable {
|
||||
func asPrettyText() -> String {
|
||||
var output = asText() + ":\n"
|
||||
for index in 1...finalSquare {
|
||||
@ -938,21 +967,23 @@ println(somethingTextRepresentable.asText())
|
||||
return output
|
||||
}
|
||||
}
|
||||
</code></pre><p>在<code>for in</code>中迭代出了<code>board</code>数组中的每一个元素:</p>
|
||||
</code></pre>
|
||||
<p>在<code>for in</code>中迭代出了<code>board</code>数组中的每一个元素:</p>
|
||||
<ul>
|
||||
<li>当从数组中迭代出的元素的值大于0时,用<code>▲</code>表示</li>
|
||||
<li>当从数组中迭代出的元素的值小于0时,用<code>▼</code>表示</li>
|
||||
<li>当从数组中迭代出的元素的值等于0时,用<code>○</code>表示</li>
|
||||
</ul>
|
||||
<p>任意<code>SankesAndLadders</code>的实例都可以使用<code>asPrettyText()</code>方法。</p>
|
||||
<pre><code>println(game.asPrettyText())
|
||||
<pre><code class="lang-swift">println(game.asPrettyText())
|
||||
// A game of Snakes and Ladders with 25 squares:
|
||||
// ○ ○ ▲ ○ ○ ▲ ○ ○ ▲ ▲ ○ ○ ○ ▼ ○ ○ ○ ○ ▼ ○ ○ ▼ ○ ▼ ○
|
||||
</code></pre><p><a name="protocol_composition"></a></p>
|
||||
</code></pre>
|
||||
<p><a name="protocol_composition"></a></p>
|
||||
<h2 id="-">协议合成</h2>
|
||||
<p>一个协议可由多个协议采用<code>protocol<SomeProtocol, AnotherProtocol></code>这样的格式进行组合,称为<code>协议合成(protocol composition)</code>。</p>
|
||||
<p>举个例子:</p>
|
||||
<pre><code>protocol Named {
|
||||
<pre><code class="lang-swift">protocol Named {
|
||||
var name: String { get }
|
||||
}
|
||||
protocol Aged {
|
||||
@ -968,11 +999,12 @@ func wishHappyBirthday(celebrator: protocol<Named, Aged>) {
|
||||
let birthdayPerson = Person(name: "Malcolm", age: 21)
|
||||
wishHappyBirthday(birthdayPerson)
|
||||
// 输出 "Happy birthday Malcolm - you're 21!
|
||||
</code></pre><p><code>Named</code>协议包含<code>String</code>类型的<code>name</code>属性;<code>Aged</code>协议包含<code>Int</code>类型的<code>age</code>属性。<code>Person</code>结构体<code>遵循</code>了这两个协议。</p>
|
||||
</code></pre>
|
||||
<p><code>Named</code>协议包含<code>String</code>类型的<code>name</code>属性;<code>Aged</code>协议包含<code>Int</code>类型的<code>age</code>属性。<code>Person</code>结构体<code>遵循</code>了这两个协议。</p>
|
||||
<p><code>wishHappyBirthday</code>函数的形参<code>celebrator</code>的类型为<code>protocol<Named,Aged></code>。可以传入任意<code>遵循</code>这两个协议的类型的实例</p>
|
||||
<blockquote>
|
||||
<p>注意:</p>
|
||||
<p><code>协议合成</code>并不会生成一个新协议类型,而是将多个协议合成为一个临时的协议,超出范围后立即失效。</p>
|
||||
<p>注意:
|
||||
<code>协议合成</code>并不会生成一个新协议类型,而是将多个协议合成为一个临时的协议,超出范围后立即失效。</p>
|
||||
</blockquote>
|
||||
<p><a name="checking_for_protocol_conformance"></a></p>
|
||||
<h2 id="-">检验协议的一致性</h2>
|
||||
@ -982,14 +1014,15 @@ wishHappyBirthday(birthdayPerson)
|
||||
<li><code>as?</code>返回一个可选值,当实例<code>遵循</code>协议时,返回该协议类型;否则返回<code>nil</code></li>
|
||||
<li><code>as</code>用以强制向下转换型。</li>
|
||||
</ul>
|
||||
<pre><code>@objc protocol HasArea {
|
||||
<pre><code class="lang-swift">@objc protocol HasArea {
|
||||
var area: Double { get }
|
||||
}
|
||||
</code></pre><blockquote>
|
||||
<p>注意:</p>
|
||||
<p><code>@objc</code>用来表示协议是可选的,也可以用来表示暴露给<code>Objective-C</code>的代码,此外,<code>@objc</code>型协议只对<code>类</code>有效,因此只能在<code>类</code>中检查协议的一致性。详情查看<em><a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/BuildingCocoaApps/index.html#//apple_ref/doc/uid/TP40014216" target="_blank">Using Siwft with Cocoa and Objectivei-c</a></em>。</p>
|
||||
</code></pre>
|
||||
<blockquote>
|
||||
<p>注意:
|
||||
<code>@objc</code>用来表示协议是可选的,也可以用来表示暴露给<code>Objective-C</code>的代码,此外,<code>@objc</code>型协议只对<code>类</code>有效,因此只能在<code>类</code>中检查协议的一致性。详情查看<em><a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/BuildingCocoaApps/index.html#//apple_ref/doc/uid/TP40014216" target="_blank">Using Siwft with Cocoa and Objectivei-c</a></em>。</p>
|
||||
</blockquote>
|
||||
<pre><code>class Circle: HasArea {
|
||||
<pre><code class="lang-swift">class Circle: HasArea {
|
||||
let pi = 3.1415927
|
||||
var radius: Double
|
||||
var area:≈radius }
|
||||
@ -999,20 +1032,23 @@ class Country: HasArea {
|
||||
var area: Double
|
||||
init(area: Double) { self.area = area }
|
||||
}
|
||||
</code></pre><p><code>Circle</code>和<code>Country</code>都遵循了<code>HasArea</code>协议,前者把<code>area</code>写为计算型属性(computed property),后者则把<code>area</code>写为存储型属性(stored property)。</p>
|
||||
</code></pre>
|
||||
<p><code>Circle</code>和<code>Country</code>都遵循了<code>HasArea</code>协议,前者把<code>area</code>写为计算型属性(computed property),后者则把<code>area</code>写为存储型属性(stored property)。</p>
|
||||
<p>如下所示,<code>Animal</code>类没有实现任何协议</p>
|
||||
<pre><code>class Animal {
|
||||
<pre><code class="lang-swift">class Animal {
|
||||
var legs: Int
|
||||
init(legs: Int) { self.legs = legs }
|
||||
}
|
||||
</code></pre><p><code>Circle,Country,Animal</code>并没有一个相同的基类,所以采用<code>AnyObject</code>类型的数组来装载在它们的实例,如下所示:</p>
|
||||
<pre><code>let objects: AnyObject[] = [
|
||||
</code></pre>
|
||||
<p><code>Circle,Country,Animal</code>并没有一个相同的基类,所以采用<code>AnyObject</code>类型的数组来装载在它们的实例,如下所示:</p>
|
||||
<pre><code class="lang-swift">let objects: AnyObject[] = [
|
||||
Circle(radius: 2.0),
|
||||
Country(area: 243_610),
|
||||
Animal(legs: 4)
|
||||
]
|
||||
</code></pre><p>如下所示,在迭代时检查<code>object</code>数组的元素是否<code>遵循</code>了<code>HasArea</code>协议:</p>
|
||||
<pre><code>for object in objects {
|
||||
</code></pre>
|
||||
<p>如下所示,在迭代时检查<code>object</code>数组的元素是否<code>遵循</code>了<code>HasArea</code>协议:</p>
|
||||
<pre><code class="lang-swift">for object in objects {
|
||||
if let objectWithArea = object as? HasArea {
|
||||
println("Area is \(objectWithArea.area)")
|
||||
} else {
|
||||
@ -1022,7 +1058,8 @@ class Country: HasArea {
|
||||
// Area is 12.5663708
|
||||
// Area is 243610.0
|
||||
// Something that doesn't have an area
|
||||
</code></pre><p>当数组中的元素遵循<code>HasArea</code>协议时,通过<code>as?</code>操作符将其<code>可选绑定(optional binding)</code>到<code>objectWithArea</code>常量上。</p>
|
||||
</code></pre>
|
||||
<p>当数组中的元素遵循<code>HasArea</code>协议时,通过<code>as?</code>操作符将其<code>可选绑定(optional binding)</code>到<code>objectWithArea</code>常量上。</p>
|
||||
<p><code>objects</code>数组中元素的类型并不会因为<code>向下转型</code>而改变,当它们被赋值给<code>objectWithArea</code>时只被视为<code>HasArea</code>类型,因此只有<code>area</code>属性能够被访问。</p>
|
||||
<p><a name="optional_protocol_requirements"></a></p>
|
||||
<h2 id="-">可选协议要求</h2>
|
||||
@ -1030,21 +1067,22 @@ class Country: HasArea {
|
||||
<p>可选协议在调用时使用<code>可选链</code>,详细内容在<a href="17_Optional_Chaining.html">可选链</a>章节中查看。</p>
|
||||
<p>像<code>someOptionalMethod?(someArgument)</code>一样,你可以在可选方法名称后加上<code>?</code>来检查该方法是否被实现。<code>可选方法</code>和<code>可选属性</code>都会返回一个<code>可选值(optional value)</code>,当其不可访问时,<code>?</code>之后语句不会执行,并返回<code>nil</code>。</p>
|
||||
<blockquote>
|
||||
<p>注意:</p>
|
||||
<p>可选协议只能在含有<code>@objc</code>前缀的协议中生效。且<code>@objc</code>的协议只能被<code>类</code>遵循。</p>
|
||||
<p>注意:
|
||||
可选协议只能在含有<code>@objc</code>前缀的协议中生效。且<code>@objc</code>的协议只能被<code>类</code>遵循。</p>
|
||||
</blockquote>
|
||||
<p><code>Counter</code>类使用<code>CounterDataSource</code>类型的外部数据源来提供<code>增量值(increment amount)</code>,如下所示:</p>
|
||||
<pre><code>@objc protocol CounterDataSource {
|
||||
<pre><code class="lang-swift">@objc protocol CounterDataSource {
|
||||
@optional func incrementForCount(count: Int) -> Int
|
||||
@optional var fixedIncrement: Int { get }
|
||||
}
|
||||
</code></pre><p><code>CounterDataSource</code>含有<code>incrementForCount</code>的<code>可选方法</code>和<code>fiexdIncrement</code>的<code>可选属性</code>。</p>
|
||||
</code></pre>
|
||||
<p><code>CounterDataSource</code>含有<code>incrementForCount</code>的<code>可选方法</code>和<code>fiexdIncrement</code>的<code>可选属性</code>。</p>
|
||||
<blockquote>
|
||||
<p>注意:</p>
|
||||
<p><code>CounterDataSource</code>中的属性和方法都是可选的,因此可以在类中声明但不实现这些成员,尽管技术上允许这样做,不过最好不要这样写。</p>
|
||||
<p>注意:
|
||||
<code>CounterDataSource</code>中的属性和方法都是可选的,因此可以在类中声明但不实现这些成员,尽管技术上允许这样做,不过最好不要这样写。</p>
|
||||
</blockquote>
|
||||
<p><code>Counter</code>类含有<code>CounterDataSource?</code>类型的可选属性<code>dataSource</code>,如下所示:</p>
|
||||
<pre><code>@objc class Counter {
|
||||
<pre><code class="lang-swift">@objc class Counter {
|
||||
var count = 0
|
||||
var dataSource: CounterDataSource?
|
||||
func increment() {
|
||||
@ -1055,7 +1093,8 @@ class Country: HasArea {
|
||||
}
|
||||
}
|
||||
}
|
||||
</code></pre><p><code>count</code>属性用于存储当前的值,<code>increment</code>方法用来为<code>count</code>赋值。</p>
|
||||
</code></pre>
|
||||
<p><code>count</code>属性用于存储当前的值,<code>increment</code>方法用来为<code>count</code>赋值。</p>
|
||||
<p><code>increment</code>方法通过<code>可选链</code>,尝试从两种<code>可选成员</code>中获取<code>count</code>。</p>
|
||||
<ol>
|
||||
<li>由于<code>dataSource</code>可能为<code>nil</code>,因此在<code>dataSource</code>后边加上了<code>?</code>标记来表明只在<code>dataSource</code>非空时才去调用incrementForCount`方法。</li>
|
||||
@ -1064,11 +1103,12 @@ class Country: HasArea {
|
||||
<p>在调用<code>incrementForCount</code>方法后,<code>Int</code>型<code>可选值</code>通过<code>可选绑定(optional binding)</code>自动拆包并赋值给常量<code>amount</code>。</p>
|
||||
<p>当<code>incrementForCount</code>不能被调用时,尝试使用<code>可选属性``fixedIncrement</code>来代替。</p>
|
||||
<p><code>ThreeSource</code>实现了<code>CounterDataSource</code>协议,如下所示:</p>
|
||||
<pre><code>class ThreeSource: CounterDataSource {
|
||||
<pre><code class="lang-swift">class ThreeSource: CounterDataSource {
|
||||
let fixedIncrement = 3
|
||||
}
|
||||
</code></pre><p>使用<code>ThreeSource</code>作为数据源开实例化一个<code>Counter</code>:</p>
|
||||
<pre><code>var counter = Counter()
|
||||
</code></pre>
|
||||
<p>使用<code>ThreeSource</code>作为数据源开实例化一个<code>Counter</code>:</p>
|
||||
<pre><code class="lang-swift">var counter = Counter()
|
||||
counter.dataSource = ThreeSource()
|
||||
for _ in 1...4 {
|
||||
counter.increment()
|
||||
@ -1078,8 +1118,9 @@ for _ in 1...4 {
|
||||
// 6
|
||||
// 9
|
||||
// 12
|
||||
</code></pre><p><code>TowardsZeroSource</code>实现了<code>CounterDataSource</code>协议中的<code>incrementForCount</code>方法,如下所示:</p>
|
||||
<pre><code>class TowardsZeroSource: CounterDataSource {
|
||||
</code></pre>
|
||||
<p><code>TowardsZeroSource</code>实现了<code>CounterDataSource</code>协议中的<code>incrementForCount</code>方法,如下所示:</p>
|
||||
<pre><code class="lang-swift">class TowardsZeroSource: CounterDataSource {
|
||||
func incrementForCount(count: Int) -> Int {
|
||||
if count == 0 {
|
||||
return 0
|
||||
@ -1090,8 +1131,9 @@ func incrementForCount(count: Int) -> Int {
|
||||
}
|
||||
}
|
||||
}
|
||||
</code></pre><p>下边是执行的代码:</p>
|
||||
<pre><code>counter.count = -4
|
||||
</code></pre>
|
||||
<p>下边是执行的代码:</p>
|
||||
<pre><code class="lang-swift">counter.count = -4
|
||||
counter.dataSource = TowardsZeroSource()
|
||||
for _ in 1...5 {
|
||||
counter.increment()
|
||||
@ -1104,6 +1146,7 @@ for _ in 1...5 {
|
||||
// 0
|
||||
</code></pre>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
</div>
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="2.22" data-basepath=".." data-revision="1402750255397">
|
||||
<div class="book" data-level="2.22" data-basepath=".." data-revision="1402759431779">
|
||||
<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,11 +587,10 @@
|
||||
|
||||
<div class="page-inner">
|
||||
|
||||
<section class="normal" id="section-gitbook_76">
|
||||
<section class="normal" id="section-gitbook_552">
|
||||
|
||||
<blockquote>
|
||||
<p>翻译:takalard</p>
|
||||
<p>校对:lifedim</p>
|
||||
<p>翻译:takalard<br>校对:lifedim </p>
|
||||
</blockquote>
|
||||
<h1 id="-">泛型</h1>
|
||||
<hr>
|
||||
@ -611,20 +610,22 @@
|
||||
<p><a name="the_problem_that_generics_solve"></a></p>
|
||||
<h2 id="-">泛型所解决的问题</h2>
|
||||
<p>这里是一个标准的,非泛型函数<code>swapTwoInts</code>,用来交换两个Int值:</p>
|
||||
<pre><code>func swapTwoInts(inout a: Int, inout b: Int)
|
||||
<pre><code class="lang-swift">func swapTwoInts(inout a: Int, inout b: Int)
|
||||
let temporaryA = a
|
||||
a = b
|
||||
b = temporaryA
|
||||
}
|
||||
</code></pre><p>这个函数使用写入读出(in-out)参数来交换<code>a</code>和<code>b</code>的值,请参考[写入读出参数][1]。</p>
|
||||
</code></pre>
|
||||
<p>这个函数使用写入读出(in-out)参数来交换<code>a</code>和<code>b</code>的值,请参考[写入读出参数][1]。</p>
|
||||
<p><code>swapTwoInts</code>函数可以交换<code>b</code>的原始值到<code>a</code>,也可以交换a的原始值到<code>b</code>,你可以调用这个函数交换两个<code>Int</code>变量值:</p>
|
||||
<pre><code>var someInt = 3
|
||||
<pre><code class="lang-swift">var someInt = 3
|
||||
var anotherInt = 107
|
||||
swapTwoInts(&someInt, &anotherInt)
|
||||
println("someInt is now \(someInt), and anotherInt is now \(anotherInt)")
|
||||
// 输出 "someInt is now 107, and anotherInt is now 3"
|
||||
</code></pre><p><code>swapTwoInts</code>函数是非常有用的,但是它只能交换<code>Int</code>值,如果你想要交换两个<code>String</code>或者<code>Double</code>,就不得不写更多的函数,如 <code>swapTwoStrings</code>和<code>swapTwoDoublesfunctions</code>,如同如下所示:</p>
|
||||
<pre><code>func swapTwoStrings(inout a: String, inout b: String) {
|
||||
</code></pre>
|
||||
<p><code>swapTwoInts</code>函数是非常有用的,但是它只能交换<code>Int</code>值,如果你想要交换两个<code>String</code>或者<code>Double</code>,就不得不写更多的函数,如 <code>swapTwoStrings</code>和<code>swapTwoDoublesfunctions</code>,如同如下所示:</p>
|
||||
<pre><code class="lang-swift">func swapTwoStrings(inout a: String, inout b: String) {
|
||||
let temporaryA = a
|
||||
a = b
|
||||
b = temporaryA
|
||||
@ -635,39 +636,41 @@ func swapTwoDoubles(inout a: Double, inout b: Double) {
|
||||
a = b
|
||||
b = temporaryA
|
||||
}
|
||||
</code></pre><p>你可能注意到 <code>swapTwoInts</code>、 <code>swapTwoStrings</code>和<code>swapTwoDoubles</code>函数功能都是相同的,唯一不同之处就在于传入的变量类型不同,分别是<code>Int</code>、<code>String</code>和<code>Double</code>。</p>
|
||||
</code></pre>
|
||||
<p>你可能注意到 <code>swapTwoInts</code>、 <code>swapTwoStrings</code>和<code>swapTwoDoubles</code>函数功能都是相同的,唯一不同之处就在于传入的变量类型不同,分别是<code>Int</code>、<code>String</code>和<code>Double</code>。</p>
|
||||
<p>但实际应用中通常需要一个用处更强大并且尽可能的考虑到更多的灵活性单个函数,可以用来交换两个任何类型值,很幸运的是,泛型代码帮你解决了这种问题。(一个这种泛型函数后面已经定义好了。)</p>
|
||||
<blockquote>
|
||||
<p>注意:
|
||||
在所有三个函数中,<code>a</code>和<code>b</code>的类型是一样的。如果<code>a</code>和<code>b</code>不是相同的类型,那它们俩就不能互换值。Swift 是类型安全的语言,所以它不允许一个<code>String</code>类型的变量和一个<code>Double</code>类型的变量互相交换值。如果一定要做,Swift 将报编译错误。</p>
|
||||
<p>注意:<br>在所有三个函数中,<code>a</code>和<code>b</code>的类型是一样的。如果<code>a</code>和<code>b</code>不是相同的类型,那它们俩就不能互换值。Swift 是类型安全的语言,所以它不允许一个<code>String</code>类型的变量和一个<code>Double</code>类型的变量互相交换值。如果一定要做,Swift 将报编译错误。</p>
|
||||
</blockquote>
|
||||
<p><a name="generic_functions"></a></p>
|
||||
<h2 id="-">泛型函数</h2>
|
||||
<p><code>泛型函数</code>可以工作于任何类型,这里是一个上面<code>swapTwoInts</code>函数的泛型版本,用于交换两个值:</p>
|
||||
<pre><code>func swapTwoValues<T>(inout a: T, inout b: T) {
|
||||
<pre><code class="lang-swift">func swapTwoValues<T>(inout a: T, inout b: T) {
|
||||
let temporaryA = a
|
||||
a = b
|
||||
b = temporaryA
|
||||
}
|
||||
</code></pre><p><code>swapTwoValues</code>函数主体和<code>swapTwoInts</code>函数是一样的,它只在第一行稍微有那么一点点不同于<code>swapTwoInts</code>,如下所示:</p>
|
||||
<pre><code>func swapTwoInts(inout a: Int, inout b: Int)
|
||||
</code></pre>
|
||||
<p><code>swapTwoValues</code>函数主体和<code>swapTwoInts</code>函数是一样的,它只在第一行稍微有那么一点点不同于<code>swapTwoInts</code>,如下所示:</p>
|
||||
<pre><code class="lang-swift">func swapTwoInts(inout a: Int, inout b: Int)
|
||||
func swapTwoValues<T>(inout a: T, inout b: T)
|
||||
</code></pre><p>这个函数的泛型版本使用了占位类型名字(通常此情况下用字母<code>T</code>来表示)来代替实际类型名(如<code>In</code>、<code>String</code>或<code>Doubl</code>)。占位类型名没有提示<code>T</code>必须是什么类型,但是它提示了<code>a</code>和<code>b</code>必须是同一类型<code>T</code>,而不管<code>T</code>表示什么类型。只有<code>swapTwoValues</code>函数在每次调用时所传入的实际类型才能决定<code>T</code>所代表的类型。</p>
|
||||
</code></pre>
|
||||
<p>这个函数的泛型版本使用了占位类型名字(通常此情况下用字母<code>T</code>来表示)来代替实际类型名(如<code>In</code>、<code>String</code>或<code>Doubl</code>)。占位类型名没有提示<code>T</code>必须是什么类型,但是它提示了<code>a</code>和<code>b</code>必须是同一类型<code>T</code>,而不管<code>T</code>表示什么类型。只有<code>swapTwoValues</code>函数在每次调用时所传入的实际类型才能决定<code>T</code>所代表的类型。</p>
|
||||
<p>另外一个不同之处在于这个泛型函数名后面跟着的展位类型名字(T)是用尖括号括起来的(<T>)。这个尖括号告诉 Swift 那个<code>T</code>是<code>swapTwoValues</code>函数所定义的一个类型。因为<code>T</code>是一个占位命名类型,Swift 不会去查找命名为T的实际类型。</p>
|
||||
<p><code>swapTwoValues</code>函数除了要求传入的两个任何类型值是同一类型外,也可以作为<code>swapTwoInts</code>函数被调用。每次<code>swapTwoValues</code>被调用,T所代表的类型值都会传给函数。</p>
|
||||
<p>在下面的两个例子中,<code>T</code>分别代表<code>Int</code>和<code>String</code>:</p>
|
||||
<pre><code>var someInt = 3
|
||||
<pre><code class="lang-swift">var someInt = 3
|
||||
var anotherInt = 107
|
||||
swapTwoValues(&someInt, &anotherInt)
|
||||
// someInt is now 107, and anotherInt is now 3
|
||||
|
||||
var someString = "hello"
|
||||
</code></pre>
|
||||
<pre><code class="lang-swift">var someString = "hello"
|
||||
var anotherString = "world"
|
||||
swapTwoValues(&someString, &anotherString)
|
||||
// someString is now "world", and anotherString is now "hello"
|
||||
</code></pre><blockquote>
|
||||
<p>注意
|
||||
上面定义的函数<code>swapTwoValues</code>是受<code>swap</code>函数启发而实现的。<code>swap</code>函数存在于 Swift 标准库,并可以在其它类中任意使用。如果你在自己代码中需要类似<code>swapTwoValues</code>函数的功能,你可以使用已存在的交换函数<code>swap</code>函数。</p>
|
||||
</code></pre>
|
||||
<blockquote>
|
||||
<p>注意<br>上面定义的函数<code>swapTwoValues</code>是受<code>swap</code>函数启发而实现的。<code>swap</code>函数存在于 Swift 标准库,并可以在其它类中任意使用。如果你在自己代码中需要类似<code>swapTwoValues</code>函数的功能,你可以使用已存在的交换函数<code>swap</code>函数。</p>
|
||||
</blockquote>
|
||||
<p><a name="type_parameters"></a></p>
|
||||
<h2 id="-">类型参数</h2>
|
||||
@ -679,16 +682,14 @@ swapTwoValues(&someString, &anotherString)
|
||||
<p>在简单的情况下,泛型函数或泛型类型需要指定一个占位类型(如上面的<code>swapTwoValues</code>泛型函数,或一个存储单一类型的泛型集,如数组),通常用一单个字母<code>T</code>来命名类型参数。不过,你可以使用任何有效的标识符来作为类型参数名。</p>
|
||||
<p>如果你使用多个参数定义更复杂的泛型函数或泛型类型,那么使用更多的描述类型参数是非常有用的。例如,Swift 字典(Dictionary)类型有两个类型参数,一个是键,另外一个是值。如果你自己写字典,你或许会定义这两个类型参数为<code>KeyType</code>和<code>ValueType</code>,用来记住它们在你的泛型代码中的作用。</p>
|
||||
<blockquote>
|
||||
<p>注意
|
||||
请始终使用大写字母开头的驼峰式命名法(例如<code>T</code>和<code>KeyType</code>)来给类型参数命名,以表明它们是类型的占位符,而非类型值。</p>
|
||||
<p>注意<br>请始终使用大写字母开头的驼峰式命名法(例如<code>T</code>和<code>KeyType</code>)来给类型参数命名,以表明它们是类型的占位符,而非类型值。</p>
|
||||
</blockquote>
|
||||
<p><a name="generic_types"></a></p>
|
||||
<h2 id="-">泛型类型</h2>
|
||||
<p>通常在泛型函数中,Swift 允许你定义你自己的泛型类型。这些自定义类、结构体和枚举作用于任何类型,如同<code>Array</code>和<code>Dictionary</code>的用法。</p>
|
||||
<p>这部分向你展示如何写一个泛型集类型--<code>Stack</code>(栈)。一个栈是一系列值域的集合,和<code>Array</code>(数组)类似,但其是一个比 Swift 的<code>Array</code>类型更多限制的集合。一个数组可以允许其里面任何位置的插入/删除操作,而栈,只允许在集合的末端添加新的项(如同<em>push</em>一个新值进栈)。同样的一个栈也只能从末端移除项(如同<em>pop</em>一个值出栈)。</p>
|
||||
<blockquote>
|
||||
<p>注意
|
||||
栈的概念已被<code>UINavigationController</code>类使用来模拟试图控制器的导航结构。你通过调用<code>UINavigationController</code>的<code>pushViewController:animated:</code>方法来为导航栈添加(add)新的试图控制器;而通过<code>popViewControllerAnimated:</code>的方法来从导航栈中移除(pop)某个试图控制器。每当你需要一个严格的<code>后进先出</code>方式来管理集合,堆栈都是最实用的模型。</p>
|
||||
<p>注意<br>栈的概念已被<code>UINavigationController</code>类使用来模拟试图控制器的导航结构。你通过调用<code>UINavigationController</code>的<code>pushViewController:animated:</code>方法来为导航栈添加(add)新的试图控制器;而通过<code>popViewControllerAnimated:</code>的方法来从导航栈中移除(pop)某个试图控制器。每当你需要一个严格的<code>后进先出</code>方式来管理集合,堆栈都是最实用的模型。</p>
|
||||
</blockquote>
|
||||
<p>下图展示了一个栈的压栈(push)/出栈(pop)的行为:</p>
|
||||
<p>![此处输入图片的描述][2]</p>
|
||||
@ -700,7 +701,7 @@ swapTwoValues(&someString, &anotherString)
|
||||
<li>移除掉一个值后,现在栈又重新只有三个值。</li>
|
||||
</ol>
|
||||
<p>这里展示了如何写一个非泛型版本的栈,<code>Int</code>值型的栈:</p>
|
||||
<pre><code>struct IntStack {
|
||||
<pre><code class="lang-swift">struct IntStack {
|
||||
var items = Int[]()
|
||||
mutating func push(item: Int) {
|
||||
items.append(item)
|
||||
@ -709,10 +710,11 @@ swapTwoValues(&someString, &anotherString)
|
||||
return items.removeLast()
|
||||
}
|
||||
}
|
||||
</code></pre><p>这个结构体在栈中使用一个<code>Array</code>性质的<code>items</code>存储值。<code>Stack</code>提供两个方法:<code>push</code>和<code>pop</code>,从栈中压进一个值和移除一个值。这些方法标记为可变的,因为它们需要修改(或<em>转换</em>)结构体的<code>items</code>数组。</p>
|
||||
</code></pre>
|
||||
<p>这个结构体在栈中使用一个<code>Array</code>性质的<code>items</code>存储值。<code>Stack</code>提供两个方法:<code>push</code>和<code>pop</code>,从栈中压进一个值和移除一个值。这些方法标记为可变的,因为它们需要修改(或<em>转换</em>)结构体的<code>items</code>数组。</p>
|
||||
<p>上面所展现的<code>IntStack</code>类型只能用于<code>Int</code>值,不过,其对于定义一个泛型<code>Stack</code>类(可以处理<em>任何</em>类型值的栈)是非常有用的。</p>
|
||||
<p>这里是一个相同代码的泛型版本:</p>
|
||||
<pre><code>struct Stack<T> {
|
||||
<pre><code class="lang-swift">struct Stack<T> {
|
||||
var items = T[]()
|
||||
mutating func push(item: T) {
|
||||
items.append(item)
|
||||
@ -721,7 +723,8 @@ swapTwoValues(&someString, &anotherString)
|
||||
return items.removeLast()
|
||||
}
|
||||
}
|
||||
</code></pre><p>注意到<code>Stack</code>的泛型版本基本上和非泛型版本相同,但是泛型版本的占位类型参数为T代替了实际<code>Int</code>类型。这种类型参数包含在一对尖括号里(<code><T></code>),紧随在结构体名字后面。</p>
|
||||
</code></pre>
|
||||
<p>注意到<code>Stack</code>的泛型版本基本上和非泛型版本相同,但是泛型版本的占位类型参数为T代替了实际<code>Int</code>类型。这种类型参数包含在一对尖括号里(<code><T></code>),紧随在结构体名字后面。</p>
|
||||
<p><code>T</code>定义了一个名为“某种类型T”的节点提供给后来用。这种将来类型可以在结构体的定义里任何地方表示为“T”。在这种情况下,<code>T</code>在如下三个地方被用作节点:</p>
|
||||
<ul>
|
||||
<li>创建一个名为<code>items</code>的属性,使用空的T类型值数组对其进行初始化;</li>
|
||||
@ -729,18 +732,20 @@ swapTwoValues(&someString, &anotherString)
|
||||
<li>指定一个<code>pop</code>方法的返回值,该返回值将是一个T类型值。</li>
|
||||
</ul>
|
||||
<p>当创建一个新单例并初始化时, 通过用一对紧随在类型名后的尖括号里写出实际指定栈用到类型,创建一个<code>Stack</code>实例,同创建<code>Array</code>和<code>Dictionary</code>一样:</p>
|
||||
<pre><code>var stackOfStrings = Stack<String>()
|
||||
<pre><code class="lang-swift">var stackOfStrings = Stack<String>()
|
||||
stackOfStrings.push("uno")
|
||||
stackOfStrings.push("dos")
|
||||
stackOfStrings.push("tres")
|
||||
stackOfStrings.push("cuatro")
|
||||
// 现在栈已经有4个string了
|
||||
</code></pre><p>下图将展示<code>stackOfStrings</code>如何<code>push</code>这四个值进栈的过程:</p>
|
||||
</code></pre>
|
||||
<p>下图将展示<code>stackOfStrings</code>如何<code>push</code>这四个值进栈的过程:</p>
|
||||
<p>![此处输入图片的描述][3]</p>
|
||||
<p>从栈中<code>pop</code>并移除值"cuatro":</p>
|
||||
<pre><code>let fromTheTop = stackOfStrings.pop()
|
||||
<pre><code class="lang-swift">let fromTheTop = stackOfStrings.pop()
|
||||
// fromTheTop is equal to "cuatro", and the stack now contains 3 strings
|
||||
</code></pre><p>下图展示了如何从栈中pop一个值的过程:
|
||||
</code></pre>
|
||||
<p>下图展示了如何从栈中pop一个值的过程:
|
||||
![此处输入图片的描述][4]</p>
|
||||
<p>由于<code>Stack</code>是泛型类型,所以在 Swift 中其可以用来创建任何有效类型的栈,这种方式如同<code>Array</code>和<code>Dictionary</code>。</p>
|
||||
<p><a name="type_constraints"></a></p>
|
||||
@ -751,13 +756,14 @@ stackOfStrings.push("cuatro")
|
||||
<p>当你创建自定义泛型类型时,你可以定义你自己的类型约束,当然,这些约束要支持泛型编程的强力特征中的多数。抽象概念如<code>可哈希</code>具有的类型特征是根据它们概念特征来界定的,而不是它们的直接类型特征。</p>
|
||||
<h3 id="-">类型约束语法</h3>
|
||||
<p>你可以写一个在一个类型参数名后面的类型约束,通过冒号分割,来作为类型参数链的一部分。这种作用于泛型函数的类型约束的基础语法如下所示(和泛型类型的语法相同):</p>
|
||||
<pre><code>func someFunction<T: SomeClass, U: SomeProtocol>(someT: T, someU: U) {
|
||||
<pre><code class="lang-swift">func someFunction<T: SomeClass, U: SomeProtocol>(someT: T, someU: U) {
|
||||
// function body goes here
|
||||
}
|
||||
</code></pre><p>上面这个假定函数有两个类型参数。第一个类型参数<code>T</code>,有一个需要<code>T</code>必须是<code>SomeClass</code>子类的类型约束;第二个类型参数<code>U</code>,有一个需要<code>U</code>必须遵循<code>SomeProtocol</code>协议的类型约束。</p>
|
||||
</code></pre>
|
||||
<p>上面这个假定函数有两个类型参数。第一个类型参数<code>T</code>,有一个需要<code>T</code>必须是<code>SomeClass</code>子类的类型约束;第二个类型参数<code>U</code>,有一个需要<code>U</code>必须遵循<code>SomeProtocol</code>协议的类型约束。</p>
|
||||
<h3 id="-">类型约束行为</h3>
|
||||
<p>这里有个名为<code>findStringIndex</code>的非泛型函数,该函数功能是去查找包含一给定<code>String</code>值的数组。若查找到匹配的字符串,<code>findStringIndex</code>函数返回该字符串在数组中的索引值(<code>Int</code>),反之则返回<code>nil</code>:</p>
|
||||
<pre><code>func findStringIndex(array: String[], valueToFind: String) -> Int? {
|
||||
<pre><code class="lang-swift">func findStringIndex(array: String[], valueToFind: String) -> Int? {
|
||||
for (index, value) in enumerate(array) {
|
||||
if value == valueToFind {
|
||||
return index
|
||||
@ -765,15 +771,17 @@ stackOfStrings.push("cuatro")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
</code></pre><p><code>findStringIndex</code>函数可以作用于查找一字符串数组中的某个字符串:</p>
|
||||
<pre><code>let strings = ["cat", "dog", "llama", "parakeet", "terrapin"]
|
||||
</code></pre>
|
||||
<p><code>findStringIndex</code>函数可以作用于查找一字符串数组中的某个字符串:</p>
|
||||
<pre><code class="lang-swift">let strings = ["cat", "dog", "llama", "parakeet", "terrapin"]
|
||||
if let foundIndex = findStringIndex(strings, "llama") {
|
||||
println("The index of llama is \(foundIndex)")
|
||||
}
|
||||
// 输出 "The index of llama is 2"
|
||||
</code></pre><p>如果只是针对字符串而言查找在数组中的某个值的索引,用处不是很大,不过,你可以写出相同功能的泛型函数<code>findIndex</code>,用某个类型<code>T</code>值替换掉提到的字符串。</p>
|
||||
</code></pre>
|
||||
<p>如果只是针对字符串而言查找在数组中的某个值的索引,用处不是很大,不过,你可以写出相同功能的泛型函数<code>findIndex</code>,用某个类型<code>T</code>值替换掉提到的字符串。</p>
|
||||
<p>这里展示如何写一个你或许期望的<code>findStringIndex</code>的泛型版本<code>findIndex</code>。请注意这个函数仍然返回<code>Int</code>,是不是有点迷惑呢,而不是泛型类型?那是因为函数返回的是一个可选的索引数,而不是从数组中得到的一个可选值。需要提醒的是,这个函数不会编译,原因在例子后面会说明:</p>
|
||||
<pre><code>func findIndex<T>(array: T[], valueToFind: T) -> Int? {
|
||||
<pre><code class="lang-swift">func findIndex<T>(array: T[], valueToFind: T) -> Int? {
|
||||
for (index, value) in enumerate(array) {
|
||||
if value == valueToFind {
|
||||
return index
|
||||
@ -781,10 +789,11 @@ if let foundIndex = findStringIndex(strings, "llama") {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
</code></pre><p>上面所写的函数不会编译。这个问题的位置在等式的检查上,<code>“if value == valueToFind”</code>。不是所有的 Swift 中的类型都可以用等式符(==)进行比较。例如,如果你创建一个你自己的类或结构体来表示一个复杂的数据模型,那么 Swift 没法猜到对于这个类或结构体而言“等于”的意思。正因如此,这部分代码不能可能保证工作于每个可能的类型<code>T</code>,当你试图编译这部分代码时估计会出现相应的错误。</p>
|
||||
</code></pre>
|
||||
<p>上面所写的函数不会编译。这个问题的位置在等式的检查上,<code>“if value == valueToFind”</code>。不是所有的 Swift 中的类型都可以用等式符(==)进行比较。例如,如果你创建一个你自己的类或结构体来表示一个复杂的数据模型,那么 Swift 没法猜到对于这个类或结构体而言“等于”的意思。正因如此,这部分代码不能可能保证工作于每个可能的类型<code>T</code>,当你试图编译这部分代码时估计会出现相应的错误。</p>
|
||||
<p>不过,所有的这些并不会让我们无从下手。Swift 标准库中定义了一个<code>Equatable</code>协议,该协议要求任何遵循的类型实现等式符(==)和不等符(!=)对任何两个该类型进行比较。所有的 Swift 标准类型自动支持<code>Equatable</code>协议。</p>
|
||||
<p>任何<code>Equatable</code>类型都可以安全的使用在<code>findIndex</code>函数中,因为其保证支持等式操作。为了说明这个事实,当你定义一个函数时,你可以写一个<code>Equatable</code>类型约束作为类型参数定义的一部分:</p>
|
||||
<pre><code>func findIndex<T: Equatable>(array: T[], valueToFind: T) -> Int? {
|
||||
<pre><code class="lang-swift">func findIndex<T: Equatable>(array: T[], valueToFind: T) -> Int? {
|
||||
for (index, value) in enumerate(array) {
|
||||
if value == valueToFind {
|
||||
return index
|
||||
@ -792,24 +801,27 @@ if let foundIndex = findStringIndex(strings, "llama") {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
</code></pre><p><code>findIndex</code>中这个单个类型参数写做:<code>T: Equatable</code>,也就意味着“任何T类型都遵循<code>Equatable</code>协议”。</p>
|
||||
</code></pre>
|
||||
<p><code>findIndex</code>中这个单个类型参数写做:<code>T: Equatable</code>,也就意味着“任何T类型都遵循<code>Equatable</code>协议”。</p>
|
||||
<p><code>findIndex</code>函数现在则可以成功的编译过,并且作用于任何遵循<code>Equatable</code>的类型,如<code>Double</code>或<code>String</code>:</p>
|
||||
<pre><code>let doubleIndex = findIndex([3.14159, 0.1, 0.25], 9.3)
|
||||
<pre><code class="lang-swift">let doubleIndex = findIndex([3.14159, 0.1, 0.25], 9.3)
|
||||
// doubleIndex is an optional Int with no value, because 9.3 is not in the array
|
||||
let stringIndex = findIndex(["Mike", "Malcolm", "Andrea"], "Andrea")
|
||||
// stringIndex is an optional Int containing a value of 2
|
||||
</code></pre><p><a name="associated_types"></a></p>
|
||||
</code></pre>
|
||||
<p><a name="associated_types"></a></p>
|
||||
<h2 id="-">关联类型</h2>
|
||||
<p>当定义一个协议时,有的时候声明一个或多个关联类型作为协议定义的一部分是非常有用的。一个关联类型给定作用于协议部分的类型一个节点名(或<em>别名</em>)。作用于关联类型上实际类型是不需要指定的,直到该协议接受。关联类型被指定为<code>typealias</code>关键字。</p>
|
||||
<h3 id="-">关联类型行为</h3>
|
||||
<p>这里是一个<code>Container</code>协议的例子,定义了一个ItemType关联类型:</p>
|
||||
<pre><code>protocol Container {
|
||||
<pre><code class="lang-swift">protocol Container {
|
||||
typealias ItemType
|
||||
mutating func append(item: ItemType)
|
||||
var count: Int { get }
|
||||
subscript(i: Int) -> ItemType { get }
|
||||
}
|
||||
</code></pre><p><code>Container</code>协议定义了三个任何容器必须支持的兼容要求:</p>
|
||||
</code></pre>
|
||||
<p><code>Container</code>协议定义了三个任何容器必须支持的兼容要求:</p>
|
||||
<ul>
|
||||
<li>必须可能通过<code>append</code>方法添加一个新item到容器里;</li>
|
||||
<li>必须可能通过使用<code>count</code>属性获取容器里items的数量,并返回一个<code>Int</code>值;</li>
|
||||
@ -820,7 +832,7 @@ let stringIndex = findIndex(["Mike", "Malcolm", "Andrea
|
||||
<p>为了定义这三个条件,<code>Container</code>协议需要一个方法指定容器里的元素将会保留,而不需要知道特定容器的类型。<code>Container</code>协议需要指定任何通过<code>append</code>方法添加到容器里的值和容器里元素是相同类型,并且通过容器下标返回的容器元素类型的值的类型是相同类型。</p>
|
||||
<p>为了达到此目的,<code>Container</code>协议声明了一个ItemType的关联类型,写作<code>typealias ItemType</code>。The protocol does not define what ItemType is an alias for—that information is left for any conforming type to provide(这个协议不会定义<code>ItemType</code>是遵循类型所提供的何种信息的别名)。尽管如此,<code>ItemType</code>别名支持一种方法识别在一个容器里的items类型,以及定义一种使用在<code>append</code>方法和下标中的类型,以便保证任何期望的<code>Container</code>的行为是强制性的。</p>
|
||||
<p>这里是一个早前IntStack类型的非泛型版本,适用于遵循Container协议:</p>
|
||||
<pre><code>struct IntStack: Container {
|
||||
<pre><code class="lang-swift">struct IntStack: Container {
|
||||
// original IntStack implementation
|
||||
var items = Int[]()
|
||||
mutating func push(item: Int) {
|
||||
@ -841,11 +853,12 @@ let stringIndex = findIndex(["Mike", "Malcolm", "Andrea
|
||||
return items[i]
|
||||
}
|
||||
}
|
||||
</code></pre><p><code>IntStack</code>类型实现了<code>Container</code>协议的所有三个要求,在<code>IntStack</code>类型的每个包含部分的功能都满足这些要求。</p>
|
||||
</code></pre>
|
||||
<p><code>IntStack</code>类型实现了<code>Container</code>协议的所有三个要求,在<code>IntStack</code>类型的每个包含部分的功能都满足这些要求。</p>
|
||||
<p>此外,<code>IntStack</code>指定了<code>Container</code>的实现,适用的ItemType被用作<code>Int</code>类型。对于这个<code>Container</code>协议实现而言,定义 <code>typealias ItemType = Int</code>,将抽象的<code>ItemType</code>类型转换为具体的<code>Int</code>类型。</p>
|
||||
<p>感谢Swift类型参考,你不用在<code>IntStack</code>定义部分声明一个具体的<code>Int</code>的<code>ItemType</code>。由于<code>IntStack</code>遵循<code>Container</code>协议的所有要求,只要通过简单的查找<code>append</code>方法的item参数类型和下标返回的类型,Swift就可以推断出合适的<code>ItemType</code>来使用。确实,如果上面的代码中你删除了 <code>typealias ItemType = Int</code>这一行,一切仍旧可以工作,因为它清楚的知道ItemType使用的是何种类型。</p>
|
||||
<p>你也可以生成遵循<code>Container</code>协议的泛型<code>Stack</code>类型:</p>
|
||||
<pre><code>struct Stack<T>: Container {
|
||||
<pre><code class="lang-swift">struct Stack<T>: Container {
|
||||
// original Stack<T> implementation
|
||||
var items = T[]()
|
||||
mutating func push(item: T) {
|
||||
@ -865,19 +878,21 @@ let stringIndex = findIndex(["Mike", "Malcolm", "Andrea
|
||||
return items[i]
|
||||
}
|
||||
}
|
||||
</code></pre><p>这个时候,占位类型参数<code>T</code>被用作<code>append</code>方法的item参数和下标的返回类型。Swift 因此可以推断出被用作这个特定容器的<code>ItemType</code>的<code>T</code>的合适类型。</p>
|
||||
</code></pre>
|
||||
<p>这个时候,占位类型参数<code>T</code>被用作<code>append</code>方法的item参数和下标的返回类型。Swift 因此可以推断出被用作这个特定容器的<code>ItemType</code>的<code>T</code>的合适类型。</p>
|
||||
<h3 id="-">扩展一个存在的类型为一指定关联类型</h3>
|
||||
<p>在[使用扩展来添加协议兼容性][6]中有描述扩展一个存在的类型添加遵循一个协议。这个类型包含一个关联类型的协议。</p>
|
||||
<p>Swift的<code>Array</code>已经提供<code>append</code>方法,一个<code>count</code>属性和通过下标来查找一个自己的元素。这三个功能都达到<code>Container</code>协议的要求。也就意味着你可以扩展<code>Array</code>去遵循<code>Container</code>协议,只要通过简单声明<code>Array</code>适用于该协议而已。如何实践这样一个空扩展,在[使用扩展来声明协议的采纳][7]中有描述这样一个实现一个空扩展的行为:</p>
|
||||
<pre><code>extension Array: Container {}
|
||||
</code></pre><p>如同上面的泛型<code>Stack</code>类型一样,<code>Array的append</code>方法和下标保证<code>Swift</code>可以推断出<code>ItemType</code>所使用的适用的类型。定义了这个扩展后,你可以将任何<code>Array</code>当作<code>Container</code>来使用。</p>
|
||||
<pre><code class="lang-swift">extension Array: Container {}
|
||||
</code></pre>
|
||||
<p>如同上面的泛型<code>Stack</code>类型一样,<code>Array的append</code>方法和下标保证<code>Swift</code>可以推断出<code>ItemType</code>所使用的适用的类型。定义了这个扩展后,你可以将任何<code>Array</code>当作<code>Container</code>来使用。</p>
|
||||
<p><a name="where_clauses"></a></p>
|
||||
<h2 id="where-">Where 语句</h2>
|
||||
<p>[类型约束][8]中描述的类型约束确保你定义关于类型参数的需求和一泛型函数或类型有关联。</p>
|
||||
<p>对于关联类型的定义需求也是非常有用的。你可以通过这样去定义<em>where语句</em>作为一个类型参数队列的一部分。一个<code>where</code>语句使你能够要求一个关联类型遵循一个特定的协议,以及(或)那个特定的类型参数和关联类型可以是相同的。你可写一个<code>where</code>语句,通过紧随放置<code>where</code>关键字在类型参数队列后面,其后跟着一个或者多个针对关联类型的约束,以及(或)一个或多个类型和关联类型的等于关系。</p>
|
||||
<p>下面的列子定义了一个名为<code>allItemsMatch</code>的泛型函数,用来检查是否两个<code>Container</code>单例包含具有相同顺序的相同元素。如果匹配到所有的元素,那么返回一个为<code>true</code>的<code>Boolean</code>值,反之,则相反。</p>
|
||||
<p>这两个容器可以被检查出是否是相同类型的容器(虽然它们可以是),但它们确实拥有相同类型的元素。这个需求通过一个类型约束和<code>where</code>语句结合来表示:</p>
|
||||
<pre><code>func allItemsMatch<
|
||||
<pre><code class="lang-swift">func allItemsMatch<
|
||||
C1: Container, C2: Container
|
||||
where C1.ItemType == C2.ItemType, C1.ItemType: Equatable>
|
||||
(someContainer: C1, anotherContainer: C2) -> Bool {
|
||||
@ -898,7 +913,8 @@ let stringIndex = findIndex(["Mike", "Malcolm", "Andrea
|
||||
return true
|
||||
|
||||
}
|
||||
</code></pre><p>这个函数用了两个参数:<code>someContainer</code>和<code>anotherContainer</code>。<code>someContainer</code>参数是类型<code>C1</code>,<code>anotherContainer</code>参数是类型<code>C2</code>。<code>C1</code>和<code>C2</code>是容器的两个占位类型参数,决定了这个函数何时被调用。</p>
|
||||
</code></pre>
|
||||
<p>这个函数用了两个参数:<code>someContainer</code>和<code>anotherContainer</code>。<code>someContainer</code>参数是类型<code>C1</code>,<code>anotherContainer</code>参数是类型<code>C2</code>。<code>C1</code>和<code>C2</code>是容器的两个占位类型参数,决定了这个函数何时被调用。</p>
|
||||
<p>这个函数的类型参数列紧随在两个类型参数需求的后面:</p>
|
||||
<ul>
|
||||
<li><code>C1</code>必须遵循<code>Container</code>协议 (写作 <code>C1: Container</code>)。</li>
|
||||
@ -918,7 +934,7 @@ let stringIndex = findIndex(["Mike", "Malcolm", "Andrea
|
||||
<p>检查完之后,函数通过<code>for-in</code>循环和半闭区间操作(..)来迭代<code>someContainer</code>中的所有元素。对于每个元素,函数检查是否<code>someContainer</code>中的元素不等于对应的<code>anotherContainer</code>中的元素,如果这两个元素不等,则这两个容器不匹配,返回<code>false</code>。</p>
|
||||
<p>如果循环体结束后未发现没有任何的不匹配,那表明两个容器匹配,函数返回<code>true</code>。</p>
|
||||
<p>这里演示了allItemsMatch函数运算的过程:</p>
|
||||
<pre><code>var stackOfStrings = Stack<String>()
|
||||
<pre><code class="lang-swift">var stackOfStrings = Stack<String>()
|
||||
stackOfStrings.push("uno")
|
||||
stackOfStrings.push("dos")
|
||||
stackOfStrings.push("tres")
|
||||
@ -931,7 +947,8 @@ if allItemsMatch(stackOfStrings, arrayOfStrings) {
|
||||
println("Not all items match.")
|
||||
}
|
||||
// 输出 "All items match."
|
||||
</code></pre><p> 上面的例子创建一个<code>Stack</code>单例来存储<code>String</code>,然后压了三个字符串进栈。这个例子也创建了一个<code>Array</code>单例,并初始化包含三个同栈里一样的原始字符串。即便栈和数组否是不同的类型,但它们都遵循<code>Container</code>协议,而且它们都包含同样的类型值。你因此可以调用<code>allItemsMatch</code>函数,用这两个容器作为它的参数。在上面的例子中,<code>allItemsMatch</code>函数正确的显示了所有的这两个容器的<code>items</code>匹配。</p>
|
||||
</code></pre>
|
||||
<p> 上面的例子创建一个<code>Stack</code>单例来存储<code>String</code>,然后压了三个字符串进栈。这个例子也创建了一个<code>Array</code>单例,并初始化包含三个同栈里一样的原始字符串。即便栈和数组否是不同的类型,但它们都遵循<code>Container</code>协议,而且它们都包含同样的类型值。你因此可以调用<code>allItemsMatch</code>函数,用这两个容器作为它的参数。在上面的例子中,<code>allItemsMatch</code>函数正确的显示了所有的这两个容器的<code>items</code>匹配。</p>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="2.23" data-basepath=".." data-revision="1402750255397">
|
||||
<div class="book" data-level="2.23" data-basepath=".." data-revision="1402759431779">
|
||||
<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,11 +587,10 @@
|
||||
|
||||
<div class="page-inner">
|
||||
|
||||
<section class="normal" id="section-gitbook_78">
|
||||
<section class="normal" id="section-gitbook_555">
|
||||
|
||||
<blockquote>
|
||||
<p>翻译:xielingwang</p>
|
||||
<p>校对:numbbbbb</p>
|
||||
<p>翻译:xielingwang<br>校对:numbbbbb </p>
|
||||
</blockquote>
|
||||
<h1 id="-">高级运算符</h1>
|
||||
<hr>
|
||||
@ -776,8 +775,7 @@ let y = x &/ 0
|
||||
<p>计算结果为 4。</p>
|
||||
<p>查阅Swift运算符的优先级和结合性的完整列表,请看<a href="../chapter3/04_Expressions.html">表达式</a>。</p>
|
||||
<blockquote>
|
||||
<p>注意:</p>
|
||||
<p>Swift的运算符较C语言和Objective-C来得更简单和保守,这意味着跟基于C的语言可能不一样。所以,在移植已有代码到Swift时,注意去确保代码按你想的那样去执行。</p>
|
||||
<p>注意:<br>Swift的运算符较C语言和Objective-C来得更简单和保守,这意味着跟基于C的语言可能不一样。所以,在移植已有代码到Swift时,注意去确保代码按你想的那样去执行。</p>
|
||||
</blockquote>
|
||||
<p><a name="operator_functions"></a></p>
|
||||
<h2 id="-">运算符函数</h2>
|
||||
@ -841,8 +839,7 @@ let afterIncrement = ++toIncrement
|
||||
// afterIncrement 现在也是 (4.0, 5.0)
|
||||
</code></pre>
|
||||
<blockquote>
|
||||
<p>注意:</p>
|
||||
<p>默认的赋值符是不可重载的。只有组合赋值符可以重载。三目条件运算符 <code>a?b:c</code> 也是不可重载。</p>
|
||||
<p>注意:<br>默认的赋值符是不可重载的。只有组合赋值符可以重载。三目条件运算符 <code>a?b:c</code> 也是不可重载。</p>
|
||||
</blockquote>
|
||||
<h3 id="-">比较运算符</h3>
|
||||
<p>Swift无所知道自定义类型是否相等或不等,因为等于或者不等于由你的代码说了算了。所以自定义的类和结构要使用比较符<code>==</code>或<code>!=</code>就需要重载。</p>
|
||||
@ -895,7 +892,7 @@ let secondVector = Vector2D(x: 3.0, y: 4.0)
|
||||
let plusMinusVector = firstVector +- secondVector
|
||||
// plusMinusVector 此时的值为 (4.0, -2.0)
|
||||
</code></pre>
|
||||
<p>这个运算符把两个向量的<code>x</code>相加,把向量的<code>y</code>相减。因为它实际是属于加减运算,所以让它保持了和加法一样的结合性和优先级(<code>left</code>和<code>140</code>)。查阅完整的Swift默认结合性和优先级的设置,请移步<a href="../chapter3/04_Expressions.html">表达式</a>;</p>
|
||||
<p>这个运算符把两个向量的<code>x</code>相加,把向量的<code>y</code>相减。因为他实际是属于加减运算,所以让它保持了和加法一样的结合性和优先级(<code>left</code>和<code>140</code>)。查阅完整的Swift默认结合性和优先级的设置,请移步<a href="../chapter3/04_Expressions.html">表达式</a>;</p>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="2" data-basepath=".." data-revision="1402750255397">
|
||||
<div class="book" data-level="2" data-basepath=".." data-revision="1402759431779">
|
||||
<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_80">
|
||||
<section class="normal" id="section-gitbook_554">
|
||||
|
||||
<h1 id="swift-">Swift 教程</h1>
|
||||
<p>本章介绍了 Swift 的各种特性及其使用方法,是全书的核心部分。</p>
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="3.1" data-basepath=".." data-revision="1402750255397">
|
||||
<div class="book" data-level="3.1" data-basepath=".." data-revision="1402759431779">
|
||||
<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,11 +587,10 @@
|
||||
|
||||
<div class="page-inner">
|
||||
|
||||
<section class="normal" id="section-gitbook_83">
|
||||
<section class="normal" id="section-gitbook_559">
|
||||
|
||||
<blockquote>
|
||||
<p>翻译:ChildhoodAndy</p>
|
||||
<p>校对:numbbbbb</p>
|
||||
<p>翻译:ChildhoodAndy<br>校对:numbbbbb</p>
|
||||
</blockquote>
|
||||
<h1 id="-">关于语言附注</h1>
|
||||
<hr>
|
||||
@ -614,14 +613,11 @@
|
||||
</ul>
|
||||
<p>举个例子,getter-setter的语法块的定义如下:</p>
|
||||
<blockquote>
|
||||
<p>GRAMMAR OF A GETTER-SETTER BLOCK</p>
|
||||
<p><em>getter-setter-block</em> → { <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/swift/grammar/getter-clause" target="_blank"><em>getter-clause</em></a> <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/swift/grammar/setter-clause" target="_blank"><em>setter-clause</em></a><em>opt</em> } | { <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/swift/grammar/setter-clause" target="_blank"><em>setter-clause</em></a> <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/swift/grammar/getter-clause" target="_blank"><em>getter-clause</em></a>}</p>
|
||||
<p>GRAMMAR OF A GETTER-SETTER BLOCK<br><em>getter-setter-block</em> → { <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/swift/grammar/getter-clause" target="_blank"><em>getter-clause</em></a> <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/swift/grammar/setter-clause" target="_blank"><em>setter-clause</em></a><em>opt</em> } | { <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/swift/grammar/setter-clause" target="_blank"><em>setter-clause</em></a> <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/swift/grammar/getter-clause" target="_blank"><em>getter-clause</em></a>}</p>
|
||||
</blockquote>
|
||||
<p>这个定义表明,一个getter-setter方法块可以由一个getter子句后跟一个可选的setter子句构成,用大括号括起来,或者由一个setter子句后跟一个getter子句构成,用大括号括起来。上述的文法产生等价于下面的两个产生,明确阐明如何二中择一:</p>
|
||||
<blockquote>
|
||||
<p>GRAMMAR OF A GETTER-SETTER BLOCK</p>
|
||||
<p>getter-setter-block → { <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/swift/grammar/getter-clause" target="_blank"><em>getter-clause</em></a> <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/swift/grammar/setter-clause" target="_blank"><em>setter-clause</em></a><em>opt</em> }</p>
|
||||
<p>getter-setter-block → { <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/swift/grammar/setter-clause" target="_blank"><em>setter-clause</em></a> <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/swift/grammar/getter-clause" target="_blank"><em>getter-clause</em></a>}</p>
|
||||
<p>GRAMMAR OF A GETTER-SETTER BLOCK<br>getter-setter-block → { <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/swift/grammar/getter-clause" target="_blank"><em>getter-clause</em></a> <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/swift/grammar/setter-clause" target="_blank"><em>setter-clause</em></a><em>opt</em> }<br>getter-setter-block → { <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/swift/grammar/setter-clause" target="_blank"><em>setter-clause</em></a> <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/swift/grammar/getter-clause" target="_blank"><em>getter-clause</em></a>}</p>
|
||||
</blockquote>
|
||||
|
||||
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="3.2" data-basepath=".." data-revision="1402750255397">
|
||||
<div class="book" data-level="3.2" data-basepath=".." data-revision="1402759431779">
|
||||
<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_89">
|
||||
<section class="normal" id="section-gitbook_567">
|
||||
|
||||
<blockquote>
|
||||
<p>翻译:superkam</p>
|
||||
@ -615,44 +615,16 @@
|
||||
<p>使用保留字(<em>reserved word</em>)作为标识符,需要在其前后增加反引号 <code>`</code>。例如,<code>class</code> 不是合法的标识符,但可以使用 <code>`class`</code>。反引号不属于标识符的一部分,<code>`x`</code> 和 <code>x</code> 表示同一标识符。</p>
|
||||
<p>闭包(<em>closure</em>)中如果没有明确指定参数名称,参数将被隐式命名为 <code>$0</code>、<code>$1</code>、<code>$2</code>... 这些命名在闭包作用域内是合法的标识符。</p>
|
||||
<blockquote>
|
||||
<p>标识符语法</p>
|
||||
<p><em>identifier</em> → <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/identifier-head" target="_blank">identifier-head</a> <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/identifier-characters" target="_blank">identifier-characters</a> <em>opt</em></p>
|
||||
<p><em>identifier</em> → ` <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/identifier-head" target="_blank">identifier-head</a> <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/identifier-characters" target="_blank">identifier-characters</a> <em>opt</em> `</p>
|
||||
<p><em>identifier</em> → <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/implicit-parameter-name" target="_blank">implicit-parameter-name</a></p>
|
||||
<p><em>identifier-list</em> → <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/identifier" target="_blank">identifier</a> | <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/identifier" target="_blank">identifier</a> , <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/identifier-list" target="_blank">identifier-list</a></p>
|
||||
<p><em>identifier-head</em> → A 到 Z 大写或小写字母</p>
|
||||
<p><em>identifier-head</em> → U+00A8, U+00AA, U+00AD, U+00AF, U+00B2–U+00B5, 或 U+00B7–U+00BA</p>
|
||||
<p><em>identifier-head</em> → U+00BC–U+00BE, U+00C0–U+00D6, U+00D8–U+00F6, 或 U+00F8–U+00FF</p>
|
||||
<p><em>identifier-head</em> → U+0100–U+02FF, U+0370–U+167F, U+1681–U+180D, 或 U+180F–U+1DBF</p>
|
||||
<p><em>identifier-head</em> → U+1E00–U+1FFF</p>
|
||||
<p><em>identifier-head</em> → U+200B–U+200D, U+202A–U+202E, U+203F–U+2040, U+2054, 或 U+2060–U+206F</p>
|
||||
<p><em>identifier-head</em> → U+2070–U+20CF, U+2100–U+218F, U+2460–U+24FF, 或 U+2776–U+2793</p>
|
||||
<p><em>identifier-head</em> → U+2C00–U+2DFF 或 U+2E80–U+2FFF</p>
|
||||
<p><em>identifier-head</em> → U+3004–U+3007, U+3021–U+302F, U+3031–U+303F, 或 U+3040–U+D7FF</p>
|
||||
<p><em>identifier-head</em> → U+F900–U+FD3D, U+FD40–U+FDCF, U+FDF0–U+FE1F, 或 U+FE30–U+FE44</p>
|
||||
<p><em>identifier-head</em> → U+FE47–U+FFFD</p>
|
||||
<p><em>identifier-head</em> → U+10000–U+1FFFD, U+20000–U+2FFFD, U+30000–U+3FFFD, 或 U+40000–U+4FFFD</p>
|
||||
<p><em>identifier-head</em> → U+50000–U+5FFFD, U+60000–U+6FFFD, U+70000–U+7FFFD, 或 U+80000–U+8FFFD</p>
|
||||
<p><em>identifier-head</em> → U+90000–U+9FFFD, U+A0000–U+AFFFD, U+B0000–U+BFFFD, 或 U+C0000–U+CFFFD</p>
|
||||
<p><em>identifier-head</em> → U+D0000–U+DFFFD 或 U+E0000–U+EFFFD</p>
|
||||
<p><em>identifier-character</em> → 数字 0 到 9</p>
|
||||
<p><em>identifier-character</em> → U+0300–U+036F, U+1DC0–U+1DFF, U+20D0–U+20FF, or U+FE20–U+FE2F</p>
|
||||
<p><em>identifier-character</em> → <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/identifier-head" target="_blank">identifier-head</a></p>
|
||||
<p><em>identifier-characters</em> → <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/identifier-character" target="_blank">identifier-character</a> <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/identifier-characters" target="_blank">identifier-characters</a> <em>opt</em></p>
|
||||
<p><em>implicit-parameter-name</em> → <strong>$</strong> <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/decimal-digits" target="_blank">decimal-digits</a></p>
|
||||
<p>标识符语法<br><em>标识符</em> → <a href="LexicalStructure.html#identifier_head"><em>标识符头(Head)</em></a> <a href="LexicalStructure.html#identifier_characters"><em>标识符字符列表</em></a> <em>可选</em><br><em>标识符</em> → <strong>`</strong> <a href="LexicalStructure.html#identifier_head"><em>标识符头(Head)</em></a> <a href="LexicalStructure.html#identifier_characters"><em>标识符字符列表</em></a> <em>可选</em> <strong>`</strong><br><em>标识符</em> → <a href="LexicalStructure.html#implicit_parameter_name"><em>隐式参数名</em></a><br><em>标识符列表</em> → <a href="LexicalStructure.html#identifier"><em>标识符</em></a> | <a href="LexicalStructure.html#identifier"><em>标识符</em></a> <strong>,</strong> <a href="LexicalStructure.html#identifier_list"><em>标识符列表</em></a><br><em>标识符头(Head)</em> → Upper- or lowercase letter A through Z<br><em>标识符头(Head)</em> → U+00A8, U+00AA, U+00AD, U+00AF, U+00B2–U+00B5, or U+00B7–U+00BA<br><em>标识符头(Head)</em> → U+00BC–U+00BE, U+00C0–U+00D6, U+00D8–U+00F6, or U+00F8–U+00FF<br><em>标识符头(Head)</em> → U+0100–U+02FF, U+0370–U+167F, U+1681–U+180D, or U+180F–U+1DBF<br><em>标识符头(Head)</em> → U+1E00–U+1FFF<br><em>标识符头(Head)</em> → U+200B–U+200D, U+202A–U+202E, U+203F–U+2040, U+2054, or U+2060–U+206F<br><em>标识符头(Head)</em> → U+2070–U+20CF, U+2100–U+218F, U+2460–U+24FF, or U+2776–U+2793<br><em>标识符头(Head)</em> → U+2C00–U+2DFF or U+2E80–U+2FFF<br><em>标识符头(Head)</em> → U+3004–U+3007, U+3021–U+302F, U+3031–U+303F, or U+3040–U+D7FF<br><em>标识符头(Head)</em> → U+F900–U+FD3D, U+FD40–U+FDCF, U+FDF0–U+FE1F, or U+FE30–U+FE44<br><em>标识符头(Head)</em> → U+FE47–U+FFFD<br><em>标识符头(Head)</em> → U+10000–U+1FFFD, U+20000–U+2FFFD, U+30000–U+3FFFD, or U+40000–U+4FFFD<br><em>标识符头(Head)</em> → U+50000–U+5FFFD, U+60000–U+6FFFD, U+70000–U+7FFFD, or U+80000–U+8FFFD<br><em>标识符头(Head)</em> → U+90000–U+9FFFD, U+A0000–U+AFFFD, U+B0000–U+BFFFD, or U+C0000–U+CFFFD<br><em>标识符头(Head)</em> → U+D0000–U+DFFFD or U+E0000–U+EFFFD<br><em>标识符字符</em> → 数值 0 到 9<br><em>标识符字符</em> → U+0300–U+036F, U+1DC0–U+1DFF, U+20D0–U+20FF, or U+FE20–U+FE2F<br><em>标识符字符</em> → <a href="LexicalStructure.html#identifier_head"><em>标识符头(Head)</em></a><br><em>标识符字符列表</em> → <a href="LexicalStructure.html#identifier_character"><em>标识符字符</em></a> <a href="LexicalStructure.html#identifier_characters"><em>标识符字符列表</em></a> <em>可选</em><br><em>隐式参数名</em> → <strong>$</strong> <a href="LexicalStructure.html#decimal_digits"><em>十进制数字列表</em></a> </p>
|
||||
</blockquote>
|
||||
<p><a name="keywords"></a></p>
|
||||
<h2 id="-">关键字</h2>
|
||||
<p>被保留的关键字(<em>keywords</em>)不允许用作标识符,除非被反引号转义,参见 <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/doc/uid/TP40014097-CH30-XID_796" target="_blank">标识符</a>。</p>
|
||||
<ul>
|
||||
<li><p><strong>用作声明的关键字:</strong> <em>class</em>、<em>deinit</em>、<em>enum</em>、<em>extension</em>、<em>func</em>、<em>import</em>、<em>init</em>、<em>let</em>、<em>protocol</em>、<em>static</em>、<em>struct</em>、<em>subscript</em>、<em>typealias</em>、<em>var</em></p>
|
||||
</li>
|
||||
<li><p><strong>用作语句的关键字:</strong> <em>break</em>、<em>case</em>、<em>continue</em>、<em>default</em>、<em>do</em>、<em>else</em>、<em>fallthrough</em>、<em>if</em>、<em>in</em>、<em>for</em>、<em>return</em>、<em>switch</em>、<em>where</em>、<em>while</em></p>
|
||||
</li>
|
||||
<li><p><strong>用作表达和类型的关键字:</strong> <em>as</em>、<em>dynamicType</em>、<em>is</em>、<em>new</em>、<em>super</em>、<em>self</em>、<em>Self</em>、<em>Type</em>、<em>__COLUMN__</em>、<em>__FILE__</em>、<em>__FUNCTION__</em>、<em>__LINE__</em></p>
|
||||
</li>
|
||||
<li><p><strong>特定上下文中被保留的关键字:</strong> <em>associativity</em>、<em>didSet</em>、<em>get</em>、<em>infix</em>、<em>inout</em>、<em>left</em>、<em>mutating</em>、<em>none</em>、<em>nonmutating</em>、<em>operator</em>、<em>override</em>、<em>postfix</em>、<em>precedence</em>、<em>prefix</em>、<em>right</em>、<em>set</em>、<em>unowned</em>、<em>unowned(safe)</em>、<em>unowned(unsafe)</em>、<em>weak</em>、<em>willSet</em>,这些关键字在特定上下文之外可以被用于标识符。</p>
|
||||
</li>
|
||||
<li><strong>用作声明的关键字:</strong> <em>class</em>、<em>deinit</em>、<em>enum</em>、<em>extension</em>、<em>func</em>、<em>import</em>、<em>init</em>、<em>let</em>、<em>protocol</em>、<em>static</em>、<em>struct</em>、<em>subscript</em>、<em>typealias</em>、<em>var</em></li>
|
||||
<li><strong>用作语句的关键字:</strong> <em>break</em>、<em>case</em>、<em>continue</em>、<em>default</em>、<em>do</em>、<em>else</em>、<em>fallthrough</em>、<em>if</em>、<em>in</em>、<em>for</em>、<em>return</em>、<em>switch</em>、<em>where</em>、<em>while</em></li>
|
||||
<li><strong>用作表达和类型的关键字:</strong> <em>as</em>、<em>dynamicType</em>、<em>is</em>、<em>new</em>、<em>super</em>、<em>self</em>、<em>Self</em>、<em>Type</em>、<em>__COLUMN__</em>、<em>__FILE__</em>、<em>__FUNCTION__</em>、<em>__LINE__</em></li>
|
||||
<li><strong>特定上下文中被保留的关键字:</strong> <em>associativity</em>、<em>didSet</em>、<em>get</em>、<em>infix</em>、<em>inout</em>、<em>left</em>、<em>mutating</em>、<em>none</em>、<em>nonmutating</em>、<em>operator</em>、<em>override</em>、<em>postfix</em>、<em>precedence</em>、<em>prefix</em>、<em>right</em>、<em>set</em>、<em>unowned</em>、<em>unowned(safe)</em>、<em>unowned(unsafe)</em>、<em>weak</em>、<em>willSet</em>,这些关键字在特定上下文之外可以被用于标识符。</li>
|
||||
</ul>
|
||||
<p><a name="literals"></a></p>
|
||||
<h2 id="-">字面量</h2>
|
||||
@ -662,8 +634,7 @@
|
||||
"Hello, world!" // 文本型字面量
|
||||
</code></pre>
|
||||
<blockquote>
|
||||
<p>字面量语法</p>
|
||||
<p><em>literal</em> → <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/integer-literal" target="_blank">integer-literal</a> | <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/floating-point-literal" target="_blank">floating-point-literal</a> | <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/string-literal" target="_blank">string-literal</a></p>
|
||||
<p>字面量语法<br><em>字面量</em> → <a href="LexicalStructure.html#integer_literal"><em>整型字面量</em></a> | <a href="LexicalStructure.html#floating_point_literal"><em>浮点数字面量</em></a> | <a href="LexicalStructure.html#string_literal"><em>字符串字面量</em></a> </p>
|
||||
</blockquote>
|
||||
<h3 id="-">整型字面量</h3>
|
||||
<p>整型字面量(<em>integer literals</em>)表示未指定精度整型数的值。整型字面量默认用十进制表示,可以加前缀来指定其他的进制,二进制字面量加 <code>0b</code>,八进制字面量加 <code>0o</code>,十六进制字面量加 <code>0x</code>。</p>
|
||||
@ -675,28 +646,7 @@
|
||||
</code></pre>
|
||||
<p>除非特殊指定,整型字面量的默认类型为 Swift 标准库类型中的 <code>Int</code>。Swift 标准库还定义了其他不同长度以及是否带符号的整数类型,请参考 <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/TheBasics.html#//apple_ref/doc/uid/TP40014097-CH5-XID_411" target="_blank">整数类型</a>。</p>
|
||||
<blockquote>
|
||||
<p>整型字面量语法</p>
|
||||
<p><em>integer-literal</em> → <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/binary-literal" target="_blank">binary-literal</a></p>
|
||||
<p><em>integer-literal</em> → <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/octal-literal" target="_blank">octal-literal</a></p>
|
||||
<p><em>integer-literal</em> → <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/decimal-literal" target="_blank">decimal-literal</a></p>
|
||||
<p><em>integer-literal</em> → <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/hexadecimal-literal" target="_blank">hexadecimal-literal</a></p>
|
||||
<p><em>binary-literal</em> → <strong>0b</strong> <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/binary-digit" target="_blank">binary-digit</a> <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/binary-literal-characters" target="_blank">binary-literal-characters</a> <em>opt</em></p>
|
||||
<p><em>binary-digit</em> → 数字 0 或 1</p>
|
||||
<p><em>binary-literal-character</em> → <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/binary-digit" target="_blank">binary-digit</a> | _</p>
|
||||
<p><em>binary-literal-characters</em> → <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/binary-literal-character" target="_blank">binary-literal-character</a> <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/binary-literal-characters" target="_blank">binary-literal-characters</a> <em>opt</em></p>
|
||||
<p><em>octal-literal</em> → <strong>0o</strong> <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/octal-digit" target="_blank">octal-digit</a> <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/octal-literal-characters" target="_blank">octal-literal-characters</a> <em>opt</em></p>
|
||||
<p><em>octal-digit</em> → 数字 0 至 7</p>
|
||||
<p><em>octal-literal-character</em> → <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/octal-digit" target="_blank">octal-digit</a> | _</p>
|
||||
<p><em>octal-literal-characters</em> → <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/octal-literal-character" target="_blank">octal-literal-character</a> <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/octal-literal-characters" target="_blank">octal-literal-characters</a> <em>opt</em></p>
|
||||
<p><em>decimal-literal</em> → <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/decimal-digit" target="_blank">decimal-digit</a> <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/decimal-literal-characters" target="_blank">decimal-literal-characters</a> <em>opt</em></p>
|
||||
<p><em>decimal-digit</em> → 数字 0 至 9</p>
|
||||
<p><em>decimal-digits</em> → <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/decimal-digit" target="_blank">decimal-digit</a> <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/decimal-digits" target="_blank">decimal-digits</a> <em>opt</em></p>
|
||||
<p><em>decimal-literal-character</em> → <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/decimal-digit" target="_blank">decimal-digit</a> | _</p>
|
||||
<p><em>decimal-literal-characters</em> → <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/decimal-literal-character" target="_blank">decimal-literal-character</a> <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/decimal-literal-characters" target="_blank">decimal-literal-characters</a> <em>opt</em></p>
|
||||
<p><em>hexadecimal-literal</em> → <strong>0x</strong> <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/hexadecimal-digit" target="_blank">hexadecimal-digit</a> <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/hexadecimal-literal-characters" target="_blank">hexadecimal-literal-characters</a> <em>opt</em></p>
|
||||
<p><em>hexadecimal-digit</em> → 数字 0 到 9, a 到 f, 或 A 到 F</p>
|
||||
<p><em>hexadecimal-literal-character</em> → <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/hexadecimal-digit" target="_blank">hexadecimal-digit</a> | _</p>
|
||||
<p><em>hexadecimal-literal-characters</em> → <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/hexadecimal-literal-character" target="_blank">hexadecimal-literal-character</a> <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/hexadecimal-literal-characters" target="_blank">hexadecimal-literal-characters</a> <em>opt</em></p>
|
||||
<p>整型字面量语法<br><em>整型字面量</em> → <a href="LexicalStructure.html#binary_literal"><em>二进制字面量</em></a><br><em>整型字面量</em> → <a href="LexicalStructure.html#octal_literal"><em>八进制字面量</em></a><br><em>整型字面量</em> → <a href="LexicalStructure.html#decimal_literal"><em>十进制字面量</em></a><br><em>整型字面量</em> → <a href="LexicalStructure.html#hexadecimal_literal"><em>十六进制字面量</em></a><br><em>二进制字面量</em> → <strong>0b</strong> <a href="LexicalStructure.html#binary_digit"><em>二进制数字</em></a> <a href="LexicalStructure.html#binary_literal_characters"><em>二进制字面量字符列表</em></a> <em>可选</em><br><em>二进制数字</em> → 数值 0 到 1<br><em>二进制字面量字符</em> → <a href="LexicalStructure.html#binary_digit"><em>二进制数字</em></a> | <strong>_</strong><br><em>二进制字面量字符列表</em> → <a href="LexicalStructure.html#binary_literal_character"><em>二进制字面量字符</em></a> <a href="LexicalStructure.html#binary_literal_characters"><em>二进制字面量字符列表</em></a> <em>可选</em><br><em>八进制字面量</em> → <strong>0o</strong> <a href="LexicalStructure.html#octal_digit"><em>八进字数字</em></a> <a href="LexicalStructure.html#octal_literal_characters"><em>八进制字符列表</em></a> <em>可选</em><br><em>八进字数字</em> → 数值 0 到 7<br><em>八进制字符</em> → <a href="LexicalStructure.html#octal_digit"><em>八进字数字</em></a> | <strong>_</strong><br><em>八进制字符列表</em> → <a href="LexicalStructure.html#octal_literal_character"><em>八进制字符</em></a> <a href="LexicalStructure.html#octal_literal_characters"><em>八进制字符列表</em></a> <em>可选</em><br><em>十进制字面量</em> → <a href="LexicalStructure.html#decimal_digit"><em>十进制数字</em></a> <a href="LexicalStructure.html#decimal_literal_characters"><em>十进制字符列表</em></a> <em>可选</em><br><em>十进制数字</em> → 数值 0 到 9<br><em>十进制数字列表</em> → <a href="LexicalStructure.html#decimal_digit"><em>十进制数字</em></a> <a href="LexicalStructure.html#decimal_digits"><em>十进制数字列表</em></a> <em>可选</em><br><em>十进制字符</em> → <a href="LexicalStructure.html#decimal_digit"><em>十进制数字</em></a> | <strong>_</strong><br><em>十进制字符列表</em> → <a href="LexicalStructure.html#decimal_literal_character"><em>十进制字符</em></a> <a href="LexicalStructure.html#decimal_literal_characters"><em>十进制字符列表</em></a> <em>可选</em><br><em>十六进制字面量</em> → <strong>0x</strong> <a href="LexicalStructure.html#hexadecimal_digit"><em>十六进制数字</em></a> <a href="LexicalStructure.html#hexadecimal_literal_characters"><em>十六进制字面量字符列表</em></a> <em>可选</em><br><em>十六进制数字</em> → 数值 0 到 9, a through f, or A through F<br><em>十六进制字符</em> → <a href="LexicalStructure.html#hexadecimal_digit"><em>十六进制数字</em></a> | <strong>_</strong><br><em>十六进制字面量字符列表</em> → <a href="LexicalStructure.html#hexadecimal_literal_character"><em>十六进制字符</em></a> <a href="LexicalStructure.html#hexadecimal_literal_characters"><em>十六进制字面量字符列表</em></a> <em>可选</em> </p>
|
||||
</blockquote>
|
||||
<h3 id="-">浮点型字面量</h3>
|
||||
<p>浮点型字面量(<em>floating-point literals</em>)表示未指定精度浮点数的值。</p>
|
||||
@ -710,21 +660,13 @@
|
||||
</code></pre>
|
||||
<p>除非特殊指定,浮点型字面量的默认类型为 Swift 标准库类型中的 <code>Double</code>,表示64位浮点数。Swift 标准库也定义 <code>Float</code> 类型,表示32位浮点数。</p>
|
||||
<blockquote>
|
||||
<p>浮点型字面量语法</p>
|
||||
<p><em>floating-point-literal</em> → <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/decimal-literal" target="_blank">decimal-literal</a> <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/decimal-fraction" target="_blank">decimal-fraction</a> <em>opt</em> <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/decimal-exponent" target="_blank">decimal-exponent</a> <em>opt</em></p>
|
||||
<p><em>floating-point-literal</em> → <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/hexadecimal-literal" target="_blank">hexadecimal-literal</a> <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/hexadecimal-fraction" target="_blank">hexadecimal-fraction</a> <em>opt</em> <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/hexadecimal-exponent" target="_blank">hexadecimal-exponent</a></p>
|
||||
<p><em>decimal-fraction</em> → . <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/decimal-literal" target="_blank">decimal-literal</a></p>
|
||||
<p><em>decimal-exponent</em> → <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/floating-point-e" target="_blank">floating-point-e</a> <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/sign" target="_blank">sign</a> <em>opt</em> <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/decimal-literal" target="_blank">decimal-literal</a></p>
|
||||
<p><em>hexadecimal-fraction</em> → . <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/hexadecimal-literal" target="_blank">hexadecimal-literal</a> <em>opt</em></p>
|
||||
<p><em>hexadecimal-exponent</em> → <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/floating-point-p" target="_blank">floating-point-p</a> <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/sign" target="_blank">sign</a> <em>opt</em> <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/hexadecimal-literal" target="_blank">hexadecimal-literal</a></p>
|
||||
<p><em>floating-point-e</em> → <strong>e</strong> | <strong>E</strong></p>
|
||||
<p><em>floating-point-p</em> → <strong>p</strong> | <strong>P</strong></p>
|
||||
<p><em>sign</em> → <strong>+</strong> | <strong>-</strong></p>
|
||||
<p>浮点型字面量语法<br><em>浮点数字面量</em> → <a href="LexicalStructure.html#decimal_literal"><em>十进制字面量</em></a> <a href="LexicalStructure.html#decimal_fraction"><em>十进制分数</em></a> <em>可选</em> <a href="LexicalStructure.html#decimal_exponent"><em>十进制指数</em></a> <em>可选</em><br><em>浮点数字面量</em> → <a href="LexicalStructure.html#hexadecimal_literal"><em>十六进制字面量</em></a> <a href="LexicalStructure.html#hexadecimal_fraction"><em>十六进制分数</em></a> <em>可选</em> <a href="LexicalStructure.html#hexadecimal_exponent"><em>十六进制指数</em></a><br><em>十进制分数</em> → <strong>.</strong> <a href="LexicalStructure.html#decimal_literal"><em>十进制字面量</em></a><br><em>十进制指数</em> → <a href="LexicalStructure.html#floating_point_e"><em>浮点数e</em></a> <a href="LexicalStructure.html#sign"><em>正负号</em></a> <em>可选</em> <a href="LexicalStructure.html#decimal_literal"><em>十进制字面量</em></a><br><em>十六进制分数</em> → <strong>.</strong> <a href="LexicalStructure.html#hexadecimal_literal"><em>十六进制字面量</em></a> <em>可选</em><br><em>十六进制指数</em> → <a href="LexicalStructure.html#floating_point_p"><em>浮点数p</em></a> <a href="LexicalStructure.html#sign"><em>正负号</em></a> <em>可选</em> <a href="LexicalStructure.html#hexadecimal_literal"><em>十六进制字面量</em></a><br><em>浮点数e</em> → <strong>e</strong> | <strong>E</strong><br><em>浮点数p</em> → <strong>p</strong> | <strong>P</strong><br><em>正负号</em> → <strong>+</strong> | <strong>-</strong> </p>
|
||||
</blockquote>
|
||||
<h3 id="-">文本型字面量</h3>
|
||||
<p>文本型字面量(<em>string literal</em>)由双引号中的字符串组成,形式如下:</p>
|
||||
<pre><code>"characters"
|
||||
</code></pre><p>文本型字面量中不能包含未转义的双引号 <code>"</code>、未转义的反斜线<code>\</code>、回车符(<em>carriage return</em>)或换行符(<em>line feed</em>)。</p>
|
||||
<pre><code class="lang-swift">"characters"
|
||||
</code></pre>
|
||||
<p>文本型字面量中不能包含未转义的双引号 <code>"</code>、未转义的反斜线<code>\</code>、回车符(<em>carriage return</em>)或换行符(<em>line feed</em>)。</p>
|
||||
<p>可以在文本型字面量中使用的转义特殊符号如下:</p>
|
||||
<ul>
|
||||
<li>空字符(Null Character)<code>\0</code></li>
|
||||
@ -751,16 +693,7 @@ var x = 3; "1 2 \(x)"
|
||||
</code></pre>
|
||||
<p>文本型字面量的默认类型为 <code>String</code>。组成字符串的字符类型为 <code>Character</code>。更多有关 <code>String</code> 和 <code>Character</code> 的信息请参照 <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/StringsAndCharacters.html#//apple_ref/doc/uid/TP40014097-CH7-XID_368" target="_blank">字符串和字符</a>。</p>
|
||||
<blockquote>
|
||||
<p>文本型字面量语法</p>
|
||||
<p><em>string-literal</em> → <strong>"</strong> <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/quoted-text" target="_blank">quoted-text</a> <strong>"</strong></p>
|
||||
<p><em>quoted-text</em> → <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/quoted-text-item" target="_blank">quoted-text-item</a> <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/quoted-text" target="_blank">quoted-text</a> <em>opt</em></p>
|
||||
<p><em>quoted-text-item</em> → <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/escaped-character" target="_blank">escaped-character</a></p>
|
||||
<p><em>quoted-text-item</em> → <strong>(</strong> <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/swift/grammar/expression" target="_blank">expression</a> <strong>)</strong></p>
|
||||
<p><em>quoted-text-item</em> → 除 <code>"</code>、<code>\</code>、<code>U+000A</code> 或 <code>U+000D</code> 以外的任何 Unicode 扩展字符集</p>
|
||||
<p><em>escaped-character</em> → <strong>\0</strong> | <strong>\</strong> | <strong>\t</strong> | <strong>\n</strong> | <strong>\r</strong> | <strong>\"</strong> | <strong>\'</strong></p>
|
||||
<p><em>escaped-character</em> → <strong>\x</strong> <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/hexadecimal-digit" target="_blank">hexadecimal-digit</a> <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/hexadecimal-digit" target="_blank">hexadecimal-digit</a></p>
|
||||
<p><em>escaped-character</em> → <strong>\u</strong> <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/hexadecimal-digit" target="_blank">hexadecimal-digit</a> <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/hexadecimal-digit" target="_blank">hexadecimal-digit</a> <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/hexadecimal-digit" target="_blank">hexadecimal-digit</a> <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/hexadecimal-digit" target="_blank">hexadecimal-digit</a></p>
|
||||
<p><em>escaped-character</em> → <strong>\U</strong> <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/hexadecimal-digit" target="_blank">hexadecimal-digit</a> <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/hexadecimal-digit" target="_blank">hexadecimal-digit</a> <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/hexadecimal-digit" target="_blank">hexadecimal-digit</a> <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/hexadecimal-digit" target="_blank">hexadecimal-digit</a> <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/hexadecimal-digit" target="_blank">hexadecimal-digit</a> <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/hexadecimal-digit" target="_blank">hexadecimal-digit</a> <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/hexadecimal-digit" target="_blank">hexadecimal-digit</a> <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/hexadecimal-digit" target="_blank">hexadecimal-digit</a></p>
|
||||
<p>字符型字面量语法<br><em>字符串字面量</em> → <strong>"</strong> <a href="LexicalStructure.html#quoted_text"><em>引用文本</em></a> <strong>"</strong><br><em>引用文本</em> → <a href="LexicalStructure.html#quoted_text_item"><em>引用文本条目</em></a> <a href="LexicalStructure.html#quoted_text"><em>引用文本</em></a> <em>可选</em><br><em>引用文本条目</em> → <a href="LexicalStructure.html#escaped_character"><em>转义字符</em></a><br><em>引用文本条目</em> → <strong>(</strong> <a href="..\chapter3\04_Expressions.html#expression"><em>表达式</em></a> <strong>)</strong><br><em>引用文本条目</em> → 除了", \, U+000A, or U+000D的所有Unicode的字符<br><em>转义字符</em> → <strong>\0</strong> | <strong>\</strong> | <strong>\t</strong> | <strong>\n</strong> | <strong>\r</strong> | <strong>\"</strong> | <strong>\'</strong><br><em>转义字符</em> → <strong>\x</strong> <a href="LexicalStructure.html#hexadecimal_digit"><em>十六进制数字</em></a> <a href="LexicalStructure.html#hexadecimal_digit"><em>十六进制数字</em></a><br><em>转义字符</em> → <strong>\u</strong> <a href="LexicalStructure.html#hexadecimal_digit"><em>十六进制数字</em></a> <a href="LexicalStructure.html#hexadecimal_digit"><em>十六进制数字</em></a> <a href="LexicalStructure.html#hexadecimal_digit"><em>十六进制数字</em></a> <a href="LexicalStructure.html#hexadecimal_digit"><em>十六进制数字</em></a><br><em>转义字符</em> → <strong>\U</strong> <a href="LexicalStructure.html#hexadecimal_digit"><em>十六进制数字</em></a> <a href="LexicalStructure.html#hexadecimal_digit"><em>十六进制数字</em></a> <a href="LexicalStructure.html#hexadecimal_digit"><em>十六进制数字</em></a> <a href="LexicalStructure.html#hexadecimal_digit"><em>十六进制数字</em></a> <a href="LexicalStructure.html#hexadecimal_digit"><em>十六进制数字</em></a> <a href="LexicalStructure.html#hexadecimal_digit"><em>十六进制数字</em></a> <a href="LexicalStructure.html#hexadecimal_digit"><em>十六进制数字</em></a> <a href="LexicalStructure.html#hexadecimal_digit"><em>十六进制数字</em></a> </p>
|
||||
</blockquote>
|
||||
<p><a name="operators"></a></p>
|
||||
<h2 id="-">运算符</h2>
|
||||
@ -769,26 +702,17 @@ var x = 3; "1 2 \(x)"
|
||||
<code>/</code>、<code>=</code>、<code>-</code>、<code>+</code>、<code>!</code>、<code>*</code>、<code>%</code>、<code><</code>、<code>></code>、<code>&</code>、<code>|</code>、<code>^</code>、<code>~</code>、<code>.</code>。也就是说,标记 <code>=</code>, <code>-></code>、<code>//</code>、<code>/*</code>、<code>*/</code>、<code>.</code> 以及一元前缀运算符 <code>&</code> 属于保留字,这些标记不能被重写或用于自定义运算符。</p>
|
||||
<p>运算符两侧的空白被用来区分该运算符是否为前缀运算符(<em>prefix operator</em>)、后缀运算符(<em>postfix operator</em>)或二元运算符(<em>binary operator</em>)。规则总结如下:</p>
|
||||
<ul>
|
||||
<li><p>如果运算符两侧都有空白或两侧都无空白,将被看作二元运算符。例如:<code>a+b</code> 和 <code>a + b</code> 中的运算符 <code>+</code> 被看作二元运算符。</p>
|
||||
</li>
|
||||
<li><p>如果运算符只有左侧空白,将被看作前缀一元运算符。例如 <code>a ++b</code> 中的 <code>++</code> 被看作前缀一元运算符。</p>
|
||||
</li>
|
||||
<li><p>如果运算符只有右侧空白,将被看作后缀一元运算符。例如 <code>a++ b</code> 中的 <code>++</code> 被看作后缀一元运算符。</p>
|
||||
</li>
|
||||
<li><p>如果运算符左侧没有空白并紧跟 <code>.</code>,将被看作后缀一元运算符。例如 <code>a++.b</code> 中的 <code>++</code> 被看作后缀一元运算符(同理, <code>a++ . b</code> 中的 <code>++</code> 是后缀一元运算符而 <code>a ++ .b</code> 中的 <code>++</code> 不是).</p>
|
||||
</li>
|
||||
<li>如果运算符两侧都有空白或两侧都无空白,将被看作二元运算符。例如:<code>a+b</code> 和 <code>a + b</code> 中的运算符 <code>+</code> 被看作二元运算符。</li>
|
||||
<li>如果运算符只有左侧空白,将被看作前缀一元运算符。例如 <code>a ++b</code> 中的 <code>++</code> 被看作前缀一元运算符。</li>
|
||||
<li>如果运算符只有右侧空白,将被看作后缀一元运算符。例如 <code>a++ b</code> 中的 <code>++</code> 被看作后缀一元运算符。</li>
|
||||
<li>如果运算符左侧没有空白并紧跟 <code>.</code>,将被看作后缀一元运算符。例如 <code>a++.b</code> 中的 <code>++</code> 被看作后缀一元运算符(同理, <code>a++ . b</code> 中的 <code>++</code> 是后缀一元运算符而 <code>a ++ .b</code> 中的 <code>++</code> 不是).</li>
|
||||
</ul>
|
||||
<p>鉴于这些规则,运算符前的字符 <code>(</code>、<code>[</code> 和 <code>{</code> ;运算符后的字符 <code>)</code>、<code>]</code> 和 <code>}</code> 以及字符 <code>,</code>、<code>;</code> 和 <code>:</code> 都将用于空白检测。</p>
|
||||
<p>以上规则需注意一点,如果运算符 <code>!</code> 或 <code>?</code> 左侧没有空白,则不管右侧是否有空白都将被看作后缀运算符。如果将 <code>?</code> 用作可选类型(<em>optional type</em>)修饰,左侧必须无空白。如果用于条件运算符 <code>? :</code>,必须两侧都有空白。</p>
|
||||
<p>在特定构成中 ,以 <code><</code> 或 <code>></code> 开头的运算符会被分离成两个或多个标记,剩余部分以同样的方式会被再次分离。因此,在 <code>Dictionary<String, Array<Int>></code> 中没有必要添加空白来消除闭合字符 <code>></code> 的歧义。在这个例子中, 闭合字符 <code>></code> 被看作单字符标记,而不会被误解为移位运算符 <code>>></code>。</p>
|
||||
<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_48" target="_blank">自定义操作符</a> 和 <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/doc/uid/TP40014097-CH34-XID_644" target="_blank">运算符声明</a>。学习如何重写现有运算符,请参考 <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">运算符方法</a>。</p>
|
||||
<blockquote>
|
||||
<p>运算符语法</p>
|
||||
<p><em>operator</em> → <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/operator-character" target="_blank">operator-character</a> <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/operator" target="_blank">operator</a> <em>opt</em></p>
|
||||
<p><em>operator-character</em> → <strong>/</strong> | <strong>=</strong> | <strong>-</strong> | <strong>+</strong> | <strong>!</strong> | <strong>*</strong> | <strong>%</strong> | <strong><</strong> | <strong>></strong> | <strong>&</strong> | <strong>|</strong> | <strong>^</strong> | <strong>~</strong> | <strong>.</strong></p>
|
||||
<p><em>binary-operator</em> → <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/operator" target="_blank">operator</a></p>
|
||||
<p><em>prefix-operator</em> → <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/operator" target="_blank">operator</a></p>
|
||||
<p><em>postfix-operator</em> → <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/operator" target="_blank">operator</a></p>
|
||||
<p>运算符语法语法<br><em>运算符</em> → <a href="LexicalStructure.html#operator_character"><em>运算符字符</em></a> <a href="LexicalStructure.html#operator"><em>运算符</em></a> <em>可选</em><br><em>运算符字符</em> → <strong>/</strong> | <strong>=</strong> | <strong>-</strong> | <strong>+</strong> | <strong>!</strong> | <strong>*</strong> | <strong>%</strong> | <strong><</strong> | <strong>></strong> | <strong>&</strong> | <strong>|</strong> | <strong>^</strong> | <strong>~</strong> | <strong>.</strong><br><em>二元运算符</em> → <a href="LexicalStructure.html#operator"><em>运算符</em></a><br><em>前置运算符</em> → <a href="LexicalStructure.html#operator"><em>运算符</em></a><br><em>后置运算符</em> → <a href="LexicalStructure.html#operator"><em>运算符</em></a> </p>
|
||||
</blockquote>
|
||||
|
||||
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="3.3" data-basepath=".." data-revision="1402750255397">
|
||||
<div class="book" data-level="3.3" data-basepath=".." data-revision="1402759431779">
|
||||
<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,11 +587,10 @@
|
||||
|
||||
<div class="page-inner">
|
||||
|
||||
<section class="normal" id="section-gitbook_85">
|
||||
<section class="normal" id="section-gitbook_561">
|
||||
|
||||
<blockquote>
|
||||
<p>翻译:lyuka</p>
|
||||
<p>校对:numbbbbb</p>
|
||||
<p>翻译:lyuka<br>校对:numbbbbb, stanzhai</p>
|
||||
</blockquote>
|
||||
<h1 id="-types-">类型(Types)</h1>
|
||||
<hr>
|
||||
@ -614,36 +613,32 @@
|
||||
<p><em>复合型类型</em>是没有名字的类型,它由 Swift 本身定义。Swift 存在两种复合型类型:函数类型和元组类型。一个复合型类型可以包含命名型类型和其它复合型类型。例如,元组类型<code>(Int, (Int, Int))</code>包含两个元素:第一个是命名型类型<code>Int</code>,第二个是另一个复合型类型<code>(Int, Int)</code>.</p>
|
||||
<p>本节讨论 Swift 语言本身定义的类型,并描述 Swift 中的类型推断行为。</p>
|
||||
<blockquote>
|
||||
<p>类型的语法:
|
||||
<em>type</em> → <em>array-type</em> | <em>function-type</em> | <em>type-identifier</em> | <em>tuple-type</em> | <em>optional-type</em> | <em>implicitly-unwrapped-optional-type</em> | protocol-composition-type | metatype-type</p>
|
||||
<p>类型语法<br><em>类型</em> → <a href="..\chapter3\03_Types.html#array_type"><em>数组类型</em></a> | <a href="..\chapter3\03_Types.html#function_type"><em>函数类型</em></a> | <a href="..\chapter3\03_Types.html#type_identifier"><em>类型标识</em></a> | <a href="..\chapter3\03_Types.html#tuple_type"><em>元组类型</em></a> | <a href="..\chapter3\03_Types.html#optional_type"><em>可选类型</em></a> | <a href="..\chapter3\03_Types.html#implicitly_unwrapped_optional_type"><em>隐式解析可选类型</em></a> | <a href="..\chapter3\03_Types.html#protocol_composition_type"><em>协议合成类型</em></a> | <a href="..\chapter3\03_Types.html#metatype_type"><em>元型类型</em></a> </p>
|
||||
</blockquote>
|
||||
<p><a name="type_annotation"></a></p>
|
||||
<h2 id="-">类型注解</h2>
|
||||
<p>类型注解显式地指定一个变量或表达式的值。类型注解始于冒号<code>:</code>终于类型,比如下面两个例子:</p>
|
||||
<pre><code class="lang-javascript"><span class="hljs-keyword">let</span> someTuple:(Double, Double) = (<span class="hljs-number">3.14159</span>, <span class="hljs-number">2.71828</span>)
|
||||
func someFunction(a: Int){ <span class="hljs-comment">/* ... */</span> }
|
||||
<pre><code class="lang-swift">let someTuple:(Double, Double) = (3.14159, 2.71828)
|
||||
func someFunction(a: Int){ /* ... */ }
|
||||
</code></pre>
|
||||
<p>在第一个例子中,表达式<code>someTuple</code>的类型被指定为<code>(Double, Double)</code>。在第二个例子中,函数<code>someFunction</code>的参数<code>a</code>的类型被指定为<code>Int</code>。</p>
|
||||
<p>类型注解可以在类型之前包含一个类型特性(type attributes)的可选列表。</p>
|
||||
<blockquote>
|
||||
<p>类型注解的语法:
|
||||
<em>type-annotation</em> → :<em>attributes</em>[opt] <em>type</em></p>
|
||||
<p>类型注解语法<br><em>类型注解</em> → <strong>:</strong> <a href="..\chapter3\06_Attributes.html#attributes"><em>特性(Attributes)列表</em></a> <em>可选</em> <a href="..\chapter3\03_Types.html#type"><em>类型</em></a> </p>
|
||||
</blockquote>
|
||||
<p><a name="type_identifier"></a></p>
|
||||
<h2 id="-">类型标识符</h2>
|
||||
<p>类型标识符引用命名型类型或者是命名型/复合型类型的别名。</p>
|
||||
<p>大多数情况下,类型标识符引用的是同名的命名型类型。例如类型标识符<code>Int</code>引用命名型类型<code>Int</code>,同样,类型标识符<code>Dictionary<String, Int></code>引用命名型类型<code>Dictionary<String, Int></code>。</p>
|
||||
<p>在两种情况下类型标识符引用的不是同名的类型。情况一,类型标识符引用的是命名型/复合型类型的类型别名。比如,在下面的例子中,类型标识符使用<code>Point</code>来引用元组<code>(Int, Int)</code>:</p>
|
||||
<pre><code class="lang-javascript">typealias Point = (Int, Int)
|
||||
<span class="hljs-keyword">let</span> origin: Point = (<span class="hljs-number">0</span>, <span class="hljs-number">0</span>)
|
||||
<pre><code class="lang-swift">typealias Point = (Int, Int)
|
||||
let origin: Point = (0, 0)
|
||||
</code></pre>
|
||||
<p>情况二,类型标识符使用dot(<code>.</code>)语法来表示在其它模块(modules)或其它类型嵌套内声明的命名型类型。例如,下面例子中的类型标识符引用在<code>ExampleModule</code>模块中声明的命名型类型<code>MyType</code>:</p>
|
||||
<pre><code class="lang-javascript"><span class="hljs-keyword">var</span> someValue: ExampleModule.MyType
|
||||
<pre><code class="lang-swift">var someValue: ExampleModule.MyType
|
||||
</code></pre>
|
||||
<blockquote>
|
||||
<p>类型标识符的语法:
|
||||
<em>type-identifier</em> → <em>type-name generic-argument-clause</em>[opt] | <em>type-name generic-argument-clause</em>[opt].<em>type-identifier</em>
|
||||
<em>type-name</em> → <em>identifier</em></p>
|
||||
<p>类型标识语法<br><em>类型标识</em> → <a href="..\chapter3\03_Types.html#type_name"><em>类型名称</em></a> <a href="GenericParametersAndArguments.html#generic_argument_clause"><em>泛型参数子句</em></a> <em>可选</em> | <a href="..\chapter3\03_Types.html#type_name"><em>类型名称</em></a> <a href="GenericParametersAndArguments.html#generic_argument_clause"><em>泛型参数子句</em></a> <em>可选</em> <strong>.</strong> <a href="..\chapter3\03_Types.html#type_identifier"><em>类型标识</em></a><br><em>类名</em> → <a href="LexicalStructure.html#identifier"><em>标识符</em></a> </p>
|
||||
</blockquote>
|
||||
<p><a name="tuple_type"></a></p>
|
||||
<h2 id="-">元组类型</h2>
|
||||
@ -651,12 +646,7 @@ func someFunction(a: Int){ <span class="hljs-comment">/* ... */</span> }
|
||||
<p>你可以使用元组类型作为一个函数的返回类型,这样就可以使函数返回多个值。你也可以命名元组类型中的元素,然后用这些名字来引用每个元素的值。元素的名字由一个标识符和<code>:</code>组成。“函数和多返回值”章节里有一个展示上述特性的例子。</p>
|
||||
<p><code>void</code>是空元组类型<code>()</code>的别名。如果括号内只有一个元素,那么该类型就是括号内元素的类型。比如,<code>(Int)</code>的类型是<code>Int</code>而不是<code>(Int)</code>。所以,只有当元组类型包含两个元素以上时才可以标记元组元素。</p>
|
||||
<blockquote>
|
||||
<p>元组类型语法:
|
||||
<em>tuple</em> → (<em>tuple-type-body</em>[opt])
|
||||
<em>tuple-type-body</em> → <em>tuple-type-element-list</em> ...[opt]
|
||||
<em>tuple-type-element-list</em> → <em>tuple-type-element</em> | <em>tuple-type-element</em>, <em>tuple-type-element-list</em>
|
||||
<em>tuple-type-element</em> → <em>attributes</em>[opt] <strong>inout</strong> [opt] <em>type</em> | <strong>inout</strong> [opt] <em>element-name type-annotation</em>
|
||||
<em>element-name</em> → <em>identifier</em></p>
|
||||
<p>元组类型语法<br><em>元组类型</em> → <strong>(</strong> <a href="..\chapter3\03_Types.html#tuple_type_body"><em>元组类型主体</em></a> <em>可选</em> <strong>)</strong><br><em>元组类型主体</em> → <a href="..\chapter3\03_Types.html#tuple_type_element_list"><em>元组类型的元素列表</em></a> <strong>...</strong> <em>可选</em><br><em>元组类型的元素列表</em> → <a href="..\chapter3\03_Types.html#tuple_type_element"><em>元组类型的元素</em></a> | <a href="..\chapter3\03_Types.html#tuple_type_element"><em>元组类型的元素</em></a> <strong>,</strong> <a href="..\chapter3\03_Types.html#tuple_type_element_list"><em>元组类型的元素列表</em></a><br><em>元组类型的元素</em> → <a href="..\chapter3\06_Attributes.html#attributes"><em>特性(Attributes)列表</em></a> <em>可选</em> <strong>inout</strong> <em>可选</em> <a href="..\chapter3\03_Types.html#type"><em>类型</em></a> | <strong>inout</strong> <em>可选</em> <a href="..\chapter3\03_Types.html#element_name"><em>元素名</em></a> <a href="..\chapter3\03_Types.html#type_annotation"><em>类型注解</em></a><br><em>元素名</em> → <a href="LexicalStructure.html#identifier"><em>标识符</em></a> </p>
|
||||
</blockquote>
|
||||
<p><a name="function_type"></a></p>
|
||||
<h2 id="-">函数类型</h2>
|
||||
@ -666,81 +656,78 @@ func someFunction(a: Int){ <span class="hljs-comment">/* ... */</span> }
|
||||
</ul>
|
||||
<p>由于 <em>参数类型</em> 和 <em>返回值类型</em> 可以是元组类型,所以函数类型可以让函数与方法支持多参数与多返回值。</p>
|
||||
<p>你可以对函数类型应用带有参数类型<code>()</code>并返回表达式类型的<code>auto_closure</code>属性(见类型属性章节)。一个自动闭包函数捕获特定表达式上的隐式闭包而非表达式本身。下面的例子使用<code>auto_closure</code>属性来定义一个很简单的assert函数:</p>
|
||||
<pre><code class="lang-javascript">func simpleAssert(condition: @auto_closure () -> Bool, message: <span class="hljs-built_in">String</span>){
|
||||
<span class="hljs-keyword">if</span> !condition(){
|
||||
<pre><code class="lang-swift">func simpleAssert(condition: @auto_closure () -> Bool, message: String){
|
||||
if !condition(){
|
||||
println(message)
|
||||
}
|
||||
}
|
||||
<span class="hljs-keyword">let</span> testNumber = <span class="hljs-number">5</span>
|
||||
simpleAssert(testNumber % <span class="hljs-number">2</span> == <span class="hljs-number">0</span>, <span class="hljs-string">"testNumber isn't an even number."</span>)
|
||||
<span class="hljs-comment">// prints "testNumber isn't an even number."</span>
|
||||
let testNumber = 5
|
||||
simpleAssert(testNumber % 2 == 0, "testNumber isn't an even number.")
|
||||
// prints "testNumber isn't an even number."
|
||||
</code></pre>
|
||||
<p>函数类型可以拥有一个可变长参数作为参数类型中的最后一个参数。从语法角度上讲,可变长参数由一个基础类型名字和<code>...</code>组成,如<code>Int...</code>。可变长参数被认为是一个包含了基础类型元素的数组。即<code>Int...</code>就是<code>Int[]</code>。关于使用可变长参数的例子,见章节“可变长参数”。</p>
|
||||
<p>为了指定一个<code>in-out</code>参数,可以在参数类型前加<code>inout</code>前缀。但是你不可以对可变长参数或返回值类型使用<code>inout</code>。关于In-Out参数的讨论见章节In-Out参数部分。</p>
|
||||
<p>柯里化函数(curried function)的类型相当于一个嵌套函数类型。例如,下面的柯里化函数<code>addTwoNumber()()</code>的类型是<code>Int -> Int -> Int</code>:</p>
|
||||
<pre><code class="lang-javascript">func addTwoNumbers(a: Int)(b: Int) -> Int{
|
||||
<span class="hljs-keyword">return</span> a + b
|
||||
<pre><code class="lang-swift">func addTwoNumbers(a: Int)(b: Int) -> Int{
|
||||
return a + b
|
||||
}
|
||||
addTwoNumbers(<span class="hljs-number">4</span>)(<span class="hljs-number">5</span>) <span class="hljs-comment">// returns 9</span>
|
||||
addTwoNumbers(4)(5) // returns 9
|
||||
</code></pre>
|
||||
<p>柯里化函数的函数类型从右向左组成一组。例如,函数类型<code>Int -> Int -> Int</code>可以被理解为<code>Int -> (Int -> Int)</code>——也就是说,一个函数传入一个<code>Int</code>然后输出作为另一个函数的输入,然后又返回一个<code>Int</code>。例如,你可以使用如下嵌套函数来重写柯里化函数<code>addTwoNumbers()()</code>:</p>
|
||||
<pre><code class="lang-javascript">func addTwoNumbers(a: Int) -> (Int -> Int){
|
||||
<pre><code class="lang-swift">func addTwoNumbers(a: Int) -> (Int -> Int){
|
||||
func addTheSecondNumber(b: Int) -> Int{
|
||||
<span class="hljs-keyword">return</span> a + b
|
||||
return a + b
|
||||
}
|
||||
<span class="hljs-keyword">return</span> addTheSecondNumber
|
||||
return addTheSecondNumber
|
||||
}
|
||||
addTwoNumbers(<span class="hljs-number">4</span>)(<span class="hljs-number">5</span>) <span class="hljs-comment">// Returns 9</span>
|
||||
addTwoNumbers(4)(5) // Returns 9
|
||||
</code></pre>
|
||||
<blockquote>
|
||||
<p>函数类型的语法:
|
||||
<em>function-type</em> → <em>type</em> <strong>-></strong> <em>type</em></p>
|
||||
<p>函数类型语法<br><em>函数类型</em> → <a href="..\chapter3\03_Types.html#type"><em>类型</em></a> <strong>-></strong> <a href="..\chapter3\03_Types.html#type"><em>类型</em></a> </p>
|
||||
</blockquote>
|
||||
<p><a name="array_type"></a></p>
|
||||
<h2 id="-">数组类型</h2>
|
||||
<p>Swift语言使用类型名紧接中括号<code>[]</code>来简化标准库中定义的命名型类型<code>Array<T></code>。换句话说,下面两个声明是等价的:</p>
|
||||
<pre><code class="lang-javascript"><span class="hljs-keyword">let</span> someArray: <span class="hljs-built_in">String</span>[] = [<span class="hljs-string">"Alex"</span>, <span class="hljs-string">"Brian"</span>, <span class="hljs-string">"Dave"</span>]
|
||||
<span class="hljs-keyword">let</span> someArray: <span class="hljs-built_in">Array</span><<span class="hljs-built_in">String</span>> = [<span class="hljs-string">"Alex"</span>, <span class="hljs-string">"Brian"</span>, <span class="hljs-string">"Dave"</span>]
|
||||
<pre><code class="lang-swift">let someArray: String[] = ["Alex", "Brian", "Dave"]
|
||||
let someArray: Array<String> = ["Alex", "Brian", "Dave"]
|
||||
</code></pre>
|
||||
<p>上面两种情况下,常量<code>someArray</code>都被声明为字符串数组。数组的元素也可以通过<code>[]</code>获取访问:<code>someArray[0]</code>是指第0个元素<code>“Alex”</code>。</p>
|
||||
<p>上面的例子同时显示,你可以使用<code>[]</code>作为初始值构造数组,空的<code>[]</code>则用来来构造指定类型的空数组。</p>
|
||||
<pre><code class="lang-javascript"><span class="hljs-keyword">var</span> emptyArray: Double[] = []
|
||||
<pre><code class="lang-swift">var emptyArray: Double[] = []
|
||||
</code></pre>
|
||||
<p>你也可以使用链接起来的多个<code>[]</code>集合来构造多维数组。例如,下例使用三个<code>[]</code>集合来构造三维整型数组:</p>
|
||||
<pre><code class="lang-javascript"><span class="hljs-keyword">var</span> array3D: Int[][][] = [[[<span class="hljs-number">1</span>, <span class="hljs-number">2</span>], [<span class="hljs-number">3</span>, <span class="hljs-number">4</span>]], [[<span class="hljs-number">5</span>, <span class="hljs-number">6</span>], [<span class="hljs-number">7</span>, <span class="hljs-number">8</span>]]]
|
||||
<pre><code class="lang-swift">var array3D: Int[][][] = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]]
|
||||
</code></pre>
|
||||
<p>访问一个多维数组的元素时,最左边的下标指向最外层数组的相应位置元素。接下来往右的下标指向第一层嵌入的相应位置元素,依次类推。这就意味着,在上面的例子中,<code>array3D[0]</code>是指<code>[[1, 2], [3, 4]]</code>,<code>array3D[0][1]</code>是指<code>[3, 4]</code>,<code>array3D[0][1][1]</code>则是指值<code>4</code>。</p>
|
||||
<p>关于Swift标准库中<code>Array</code>类型的细节讨论,见章节Arrays。</p>
|
||||
<blockquote>
|
||||
<p>数组类型的语法:
|
||||
<em>array-type</em> → <em>type</em><code>[ ]</code> | <em>array-type</em><code>[ ]</code></p>
|
||||
<p>数组类型语法<br><em>数组类型</em> → <a href="..\chapter3\03_Types.html#type"><em>类型</em></a> <strong>[</strong> <strong>]</strong> | <a href="..\chapter3\03_Types.html#array_type"><em>数组类型</em></a> <strong>[</strong> <strong>]</strong> </p>
|
||||
</blockquote>
|
||||
<p><a name="optional_type"></a></p>
|
||||
<h2 id="-">可选类型</h2>
|
||||
<p>Swift定义后缀<code>?</code>来作为标准库中的定义的命名型类型<code>Optional<T></code>的简写。换句话说,下面两个声明是等价的:</p>
|
||||
<pre><code class="lang-javascript"><span class="hljs-keyword">var</span> optionalInteger: Int?
|
||||
<span class="hljs-keyword">var</span> optionalInteger: Optional<Int>
|
||||
<pre><code class="lang-swift">var optionalInteger: Int?
|
||||
var optionalInteger: Optional<Int>
|
||||
</code></pre>
|
||||
<p>在上述两种情况下,变量<code>optionalInteger</code>都被声明为可选整型类型。注意在类型和<code>?</code>之间没有空格。</p>
|
||||
<p>类型<code>Optional<T></code>是一个枚举,有两种形式,<code>None</code>和<code>Some(T)</code>,又来代表可能出现或可能不出现的值。任意类型都可以被显式的声明(或隐式的转换)为可选类型。当声明一个可选类型时,确保使用括号给<code>?</code>提供合适的作用范围。比如说,声明一个整型的可选数组,应写作<code>(Int[])?</code>,写成<code>Int[]?</code>的话则会出错。</p>
|
||||
<p>如果你在声明或定义可选变量或特性的时候没有提供初始值,它的值则会自动赋成缺省值<code>nil</code>。</p>
|
||||
<p>可选符合<code>LogicValue</code>协议,因此可以出现在布尔值环境下。此时,如果一个可选类型<code>T?</code>实例包含有类型为<code>T</code>的值(也就是说值为<code>Optional.Some(T)</code>),那么此可选类型就为<code>true</code>,否则为<code>false</code>。</p>
|
||||
<p>如果一个可选类型的实例包含一个值,那么你就可以使用后缀操作符<code>!</code>来获取该值,正如下面描述的:</p>
|
||||
<pre><code class="lang-javascript">optionalInteger = <span class="hljs-number">42</span>
|
||||
optionalInteger! <span class="hljs-comment">// 42</span>
|
||||
<pre><code class="lang-swift">optionalInteger = 42
|
||||
optionalInteger! // 42
|
||||
</code></pre>
|
||||
<p>使用<code>!</code>操作符获取值为<code>nil</code>的可选项会导致运行错误(runtime error)。</p>
|
||||
<p>你也可以使用可选链和可选绑定来选择性的执行可选表达式上的操作。如果值为<code>nil</code>,不会执行任何操作因此也就没有运行错误产生。</p>
|
||||
<p>更多细节以及更多如何使用可选类型的例子,见章节“可选”。</p>
|
||||
<blockquote>
|
||||
<p>可选类型语法:
|
||||
<em>optional-type</em> → <em>type</em>?</p>
|
||||
<p>可选类型语法<br><em>可选类型</em> → <a href="..\chapter3\03_Types.html#type"><em>类型</em></a> <strong>?</strong> </p>
|
||||
</blockquote>
|
||||
<p><a name="implicitly_unwrapped_optional_type"></a></p>
|
||||
<h2 id="-">隐式解析可选类型</h2>
|
||||
<p>Swift语言定义后缀<code>!</code>作为标准库中命名类型<code>ImplicitlyUnwrappedOptional<T></code>的简写。换句话说,下面两个声明等价:</p>
|
||||
<pre><code class="lang-javascript"><span class="hljs-keyword">var</span> implicitlyUnwrappedString: <span class="hljs-built_in">String</span>!
|
||||
<span class="hljs-keyword">var</span> implicitlyUnwrappedString: ImplicitlyUnwrappedOptional<<span class="hljs-built_in">String</span>>
|
||||
<pre><code class="lang-swift">var implicitlyUnwrappedString: String!
|
||||
var implicitlyUnwrappedString: ImplicitlyUnwrappedOptional<String>
|
||||
</code></pre>
|
||||
<p>上述两种情况下,变量<code>implicitlyUnwrappedString</code>被声明为一个隐式解析可选类型的字符串。注意类型与<code>!</code>之间没有空格。</p>
|
||||
<p>你可以在使用可选的地方同样使用隐式解析可选。比如,你可以将隐式解析可选的值赋给变量、常量和可选特性,反之亦然。</p>
|
||||
@ -749,47 +736,42 @@ optionalInteger! <span class="hljs-comment">// 42</span>
|
||||
<p>使用可选链会选择性的执行隐式解析可选表达式上的某一个操作。如果值为<code>nil</code>,就不会执行任何操作,因此也不会产生运行错误。</p>
|
||||
<p>关于隐式解析可选的更多细节,见章节“隐式解析可选”。</p>
|
||||
<blockquote>
|
||||
<p>隐式解析可选的语法:
|
||||
implicitly-unwrapped-optional-type → type!</p>
|
||||
<p>隐式解析可选类型(Implicitly Unwrapped Optional Type)语法<br><em>隐式解析可选类型</em> → <a href="..\chapter3\03_Types.html#type"><em>类型</em></a> <strong>!</strong> </p>
|
||||
</blockquote>
|
||||
<p><a name="protocol_composition_type"></a></p>
|
||||
<h2 id="-">协议合成类型</h2>
|
||||
<p>协议合成类型是一种符合每个协议的指定协议列表类型。协议合成类型可能会用在类型注解和泛型参数中。</p>
|
||||
<p>协议合成类型的形式如下:</p>
|
||||
<pre><code class="lang-javascript">protocol<Protocol <span class="hljs-number">1</span>, Procotol <span class="hljs-number">2</span>>
|
||||
<pre><code class="lang-swift">protocol<Protocol 1, Procotol 2>
|
||||
</code></pre>
|
||||
<p>协议合成类型允许你指定一个值,其类型可以适配多个协议的条件,而且不需要定义一个新的命名型协议来继承其它想要适配的各个协议。比如,协议合成类型<code>protocol<Protocol A, Protocol B, Protocol C></code>等效于一个从<code>Protocol A</code>,<code>Protocol B</code>, <code>Protocol C</code>继承而来的新协议<code>Protocol D</code>,很显然这样做有效率的多,甚至不需引入一个新名字。</p>
|
||||
<p>协议合成列表中的每项必须是协议名或协议合成类型的类型别名。如果列表为空,它就会指定一个空协议合成列表,这样每个类型都能适配。</p>
|
||||
<blockquote>
|
||||
<p>协议合成类型的语法:
|
||||
<em>protocol-composition-type</em> → <strong>protocol</strong> <<em>protocol-identifier-list[opt]</em>>
|
||||
<em>protocol-identifier-list</em> → <em>protocol-identifier</em> | <em>protocol-identifier, protocol-identifier-list</em>
|
||||
<em>protocol-identifier</em> → <em>type-identifier</em></p>
|
||||
<p>协议合成类型语法<br><em>协议合成类型</em> → <strong>protocol</strong> <strong><</strong> <a href="..\chapter3\03_Types.html#protocol_identifier_list"><em>协议标识符列表</em></a> <em>可选</em> <strong>></strong><br><em>协议标识符列表</em> → <a href="..\chapter3\03_Types.html#protocol_identifier"><em>协议标识符</em></a> | <a href="..\chapter3\03_Types.html#protocol_identifier"><em>协议标识符</em></a> <strong>,</strong> <a href="..\chapter3\03_Types.html#protocol_identifier_list"><em>协议标识符列表</em></a><br><em>协议标识符</em> → <a href="..\chapter3\03_Types.html#type_identifier"><em>类型标识</em></a> </p>
|
||||
</blockquote>
|
||||
<p><a name="metatype_type"></a></p>
|
||||
<h2 id="-">元类型</h2>
|
||||
<p>元类型是指所有类型的类型,包括类、结构体、枚举和协议。</p>
|
||||
<p>类、结构体或枚举类型的元类型是相应的类型名紧跟<code>.Type</code>。协议类型的元类型——并不是运行时适配该协议的具体类型——是该协议名字紧跟<code>.Protocol</code>。比如,类<code>SomeClass</code>的元类型就是<code>SomeClass.Type</code>,协议<code>SomeProtocol</code>的元类型就是<code>SomeProtocal.Protocol</code>。</p>
|
||||
<p>你可以使用后缀<code>self</code>表达式来获取类型。比如,<code>SomeClass.self</code>返回<code>SomeClass</code>本身,而不是<code>SomeClass</code>的一个实例。同样,<code>SomeProtocol.self</code>返回<code>SomeProtocol</code>本身,而不是运行时适配<code>SomeProtocol</code>的某个类型的实例。还可以对类型的实例使用<code>dynamicType</code>表达式来获取该实例在运行阶段的类型,如下所示:</p>
|
||||
<pre><code class="lang-javascript"><span class="hljs-keyword">class</span> SomeBaseClass {
|
||||
<span class="hljs-keyword">class</span> func printClassName() {
|
||||
println(<span class="hljs-string">"SomeBaseClass"</span>)
|
||||
<pre><code class="lang-swift">class SomeBaseClass {
|
||||
class func printClassName() {
|
||||
println("SomeBaseClass")
|
||||
}
|
||||
}
|
||||
<span class="hljs-keyword">class</span> SomeSubClass: SomeBaseClass {
|
||||
override <span class="hljs-keyword">class</span> func printClassName() {
|
||||
println(<span class="hljs-string">"SomeSubClass"</span>)
|
||||
class SomeSubClass: SomeBaseClass {
|
||||
override class func printClassName() {
|
||||
println("SomeSubClass")
|
||||
}
|
||||
}
|
||||
<span class="hljs-keyword">let</span> someInstance: SomeBaseClass = SomeSubClass()
|
||||
<span class="hljs-comment">// someInstance is of type SomeBaseClass at compile time, but</span>
|
||||
<span class="hljs-comment">// someInstance is of type SomeSubClass at runtime</span>
|
||||
let someInstance: SomeBaseClass = SomeSubClass()
|
||||
// someInstance is of type SomeBaseClass at compile time, but
|
||||
// someInstance is of type SomeSubClass at runtime
|
||||
someInstance.dynamicType.printClassName()
|
||||
<span class="hljs-comment">// prints "SomeSubClass</span>
|
||||
// prints "SomeSubClass
|
||||
</code></pre>
|
||||
<blockquote>
|
||||
<p>元类型的语法:
|
||||
<em>metatype-type</em> → <em>type</em>.<strong>Type</strong> | <em>type</em>.<strong>Protocol</strong></p>
|
||||
<p>元(Metatype)类型语法<br><em>元类型</em> → <a href="..\chapter3\03_Types.html#type"><em>类型</em></a> <strong>.</strong> <strong>Type</strong> | <a href="..\chapter3\03_Types.html#type"><em>类型</em></a> <strong>.</strong> <strong>Protocol</strong> x</p>
|
||||
</blockquote>
|
||||
<p><a name="type_inheritance_clause"></a></p>
|
||||
<h2 id="-">类型继承子句</h2>
|
||||
@ -798,17 +780,15 @@ someInstance.dynamicType.printClassName()
|
||||
<p>其它命名型类型可能只继承或适配一个协议列表。协议类型可能继承于其它任意数量的协议。当一个协议类型继承于其它协议时,其它协议的条件集合会被集成在一起,然后其它从当前协议继承的任意类型必须适配所有这些条件。</p>
|
||||
<p>枚举定义中的类型继承子句可以是一个协议列表,或是指定原始值的枚举,一个单独的指定原始值类型的命名型类型。使用类型继承子句来指定原始值类型的枚举定义的例子,见章节“原始值”。</p>
|
||||
<blockquote>
|
||||
<p>类型继承子句的语法:
|
||||
<em>type-inheritance-clause</em> → :<em>type-inheritance-list</em>
|
||||
<em>type-inheritance-list</em> → <em>type-identifier</em> | <em>type-identifier</em>, <em>type-inheritance-list</em></p>
|
||||
<p>类型继承子句语法<br><em>类型继承子句</em> → <strong>:</strong> <a href="..\chapter3\03_Types.html#type_inheritance_list"><em>类型继承列表</em></a><br><em>类型继承列表</em> → <a href="..\chapter3\03_Types.html#type_identifier"><em>类型标识</em></a> | <a href="..\chapter3\03_Types.html#type_identifier"><em>类型标识</em></a> <strong>,</strong> <a href="..\chapter3\03_Types.html#type_inheritance_list"><em>类型继承列表</em></a></p>
|
||||
</blockquote>
|
||||
<p><a name="type_inference"></a></p>
|
||||
<h2 id="-">类型推断</h2>
|
||||
<p>Swift广泛的使用类型推断,从而允许你可以忽略很多变量和表达式的类型或部分类型。比如,对于<code>var x: Int = 0</code>,你可以完全忽略类型而简写成<code>var x = 0</code>——编译器会正确的推断出<code>x</code>的类型<code>Int</code>。类似的,当完整的类型可以从上下文推断出来时,你也可以忽略类型的一部分。比如,如果你写了<code>let dict: Dictionary = ["A": 1]</code>,编译提也能推断出<code>dict</code>的类型是<code>Dictionary<String, Int></code>。</p>
|
||||
<p>在上面的两个例子中,类型信息从表达式树(expression tree)的叶子节点传向根节点。也就是说,<code>var x: Int = 0</code>中<code>x</code>的类型首先根据<code>0</code>的类型进行推断,然后将该类型信息传递到根节点(变量<code>x</code>)。</p>
|
||||
<p>在Swift中,类型信息也可以反方向流动——从根节点传向叶子节点。在下面的例子中,常量<code>eFloat</code>上的显式类型注解(<code>:Float</code>)导致数字字面量<code>2.71828</code>的类型是<code>Float</code>而非<code>Double</code>。</p>
|
||||
<pre><code class="lang-javascript"><span class="hljs-keyword">let</span> e = <span class="hljs-number">2.71828</span> <span class="hljs-comment">// The type of e is inferred to be Double.</span>
|
||||
<span class="hljs-keyword">let</span> eFloat: Float = <span class="hljs-number">2.71828</span> <span class="hljs-comment">// The type of eFloat is Float.</span>
|
||||
<pre><code class="lang-swift">let e = 2.71828 // The type of e is inferred to be Double.
|
||||
let eFloat: Float = 2.71828 // The type of eFloat is Float.
|
||||
</code></pre>
|
||||
<p>Swift中的类型推断在单独的表达式或语句水平上进行。这意味着所有用于推断类型的信息必须可以从表达式或其某个子表达式的类型检查中获取。</p>
|
||||
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="3.4" data-basepath=".." data-revision="1402750255397">
|
||||
<div class="book" data-level="3.4" data-basepath=".." data-revision="1402759431779">
|
||||
<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,11 +587,10 @@
|
||||
|
||||
<div class="page-inner">
|
||||
|
||||
<section class="normal" id="section-gitbook_87">
|
||||
<section class="normal" id="section-gitbook_563">
|
||||
|
||||
<blockquote>
|
||||
<p>翻译:sg552</p>
|
||||
<p>校对:numbbbbb</p>
|
||||
<p>翻译:sg552<br>校对:numbbbbb, stanzhai</p>
|
||||
</blockquote>
|
||||
<h1 id="-expressions-">表达式(Expressions)</h1>
|
||||
<hr>
|
||||
@ -608,9 +607,7 @@
|
||||
<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>
|
||||
<p>表达式语法<br><em>表达式</em> → <a href="..\chapter3\04_Expressions.html#prefix_expression"><em>前置表达式</em></a> <a href="..\chapter3\04_Expressions.html#binary_expressions"><em>二元表达式列表</em></a> <em>可选</em><br><em>表达式列表</em> → <a href="..\chapter3\04_Expressions.html#expression"><em>表达式</em></a> | <a href="..\chapter3\04_Expressions.html#expression"><em>表达式</em></a> <strong>,</strong> <a href="..\chapter3\04_Expressions.html#expression_list"><em>表达式列表</em></a> </p>
|
||||
</blockquote>
|
||||
<p><a name="prefix_expressions"></a></p>
|
||||
<h2 id="-prefix-expressions-">前缀表达式(Prefix Expressions)</h2>
|
||||
@ -627,15 +624,14 @@
|
||||
<p>对于这些操作符的使用,请参见: Basic Operators and Advanced Operators</p>
|
||||
<p>作为对上面标准库运算符的补充,你也可以对 某个函数的参数使用 '&'运算符。 更多信息,请参见: "In-Out parameters".</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> → &<em>identifier</em></p>
|
||||
<p>前置表达式语法<br><em>前置表达式</em> → <a href="LexicalStructure.html#prefix_operator"><em>前置运算符</em></a> <em>可选</em> <a href="..\chapter3\04_Expressions.html#postfix_expression"><em>后置表达式</em></a><br><em>前置表达式</em> → <a href="..\chapter3\04_Expressions.html#in_out_expression"><em>写入写出(in-out)表达式</em></a><br><em>写入写出(in-out)表达式</em> → <strong>&</strong> <a href="LexicalStructure.html#identifier"><em>标识符</em></a> </p>
|
||||
</blockquote>
|
||||
<p><a name="binary_expressions"></a></p>
|
||||
<h2 id="-binary-expressions-">二元表达式(Binary Expressions)</h2>
|
||||
<p>二元表达式由 "左边参数" + "二元运算符" + "右边参数" 组成, 它有如下的形式:</p>
|
||||
<p> <code>left-hand argument</code> <code>operator</code> <code>right-hand argument</code></p>
|
||||
<blockquote>
|
||||
<p><code>left-hand argument</code> <code>operator</code> <code>right-hand argument</code></p>
|
||||
</blockquote>
|
||||
<p>Swift 标准库提供了如下的二元运算符:</p>
|
||||
<ul>
|
||||
<li>求幂相关(无结合,优先级160)<ul>
|
||||
@ -731,55 +727,50 @@
|
||||
</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>
|
||||
<p>注意<br>在解析时, 一个二元表达式表示为一个一级数组(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>
|
||||
<p></p>
|
||||
|
||||
<blockquote>
|
||||
<p>二元表达式语法<br><em>二元表达式</em> → <a href="LexicalStructure.html#binary_operator"><em>二元运算符</em></a> <a href="..\chapter3\04_Expressions.html#prefix_expression"><em>前置表达式</em></a><br><em>二元表达式</em> → <a href="..\chapter3\04_Expressions.html#assignment_operator"><em>赋值运算符</em></a> <a href="..\chapter3\04_Expressions.html#prefix_expression"><em>前置表达式</em></a><br><em>二元表达式</em> → <a href="..\chapter3\04_Expressions.html#conditional_operator"><em>条件运算符</em></a> <a href="..\chapter3\04_Expressions.html#prefix_expression"><em>前置表达式</em></a><br><em>二元表达式</em> → <a href="..\chapter3\04_Expressions.html#type_casting_operator"><em>类型转换运算符</em></a><br><em>二元表达式列表</em> → <a href="..\chapter3\04_Expressions.html#binary_expression"><em>二元表达式</em></a> <a href="..\chapter3\04_Expressions.html#binary_expressions"><em>二元表达式列表</em></a> <em>可选</em> </p>
|
||||
</blockquote>
|
||||
<p><a name="assignment_operator"></a></p>
|
||||
<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>
|
||||
<blockquote>
|
||||
<p><code>expression</code> = <code>value</code></p>
|
||||
</blockquote>
|
||||
<p>就是把右边的 <em>value</em> 赋值给左边的 <em>expression</em>. 如果左边的<em>expression</em> 需要接收多个参数(是一个tuple ),那么右边必须也是一个具有同样数量参数的tuple. (允许嵌套的tuple)</p>
|
||||
<pre><code class="lang-swift">(a, _, (b, c)) = ("test", 9.45, (12, 3))
|
||||
// a is "test", b is 12, c is 3, and 9.45 is ignored
|
||||
</code></pre>
|
||||
<p>赋值运算符不返回任何值。</p>
|
||||
<blockquote>
|
||||
<p>赋值表达式的语法</p>
|
||||
<p><em>assignment-operator</em> → =</p>
|
||||
<p>赋值运算符语法<br><em>赋值运算符</em> → <strong>=</strong> </p>
|
||||
</blockquote>
|
||||
<p><a name="ternary_conditional_operator"></a></p>
|
||||
<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>
|
||||
<blockquote>
|
||||
<p><code>condition</code> ? <code>expression used if true</code> : <code>expression used if false</code></p>
|
||||
</blockquote>
|
||||
<p>如果 <code>condition</code> 是true, 那么返回 第一个表达式的值(此时不会调用第二个表达式), 否则返回第二个表达式的值(此时不会调用第一个表达式)。</p>
|
||||
<p>想看三元条件运算符的例子,请参见: Ternary Conditional Operator.</p>
|
||||
<blockquote>
|
||||
<p>三元条件表达式</p>
|
||||
<p><code>conditional-operator</code> → ?<code>expression</code>:</p>
|
||||
<p>三元条件运算符语法<br><em>三元条件运算符</em> → <strong>?</strong> <a href="..\chapter3\04_Expressions.html#expression"><em>表达式</em></a> <strong>:</strong> </p>
|
||||
</blockquote>
|
||||
<p><a name="type-casting_operators"></a></p>
|
||||
<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>
|
||||
<blockquote>
|
||||
<p><code>expression</code> as <code>type</code><br><code>expression</code> as? <code>type</code><br><code>expression</code> is <code>type</code> </p>
|
||||
</blockquote>
|
||||
<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>
|
||||
<li>如果类型转换成功, 那么目标表达式就会返回指定类型的实例(instance). 例如:把子类(subclass)变成父类(superclass)时.</li>
|
||||
<li>如果转换失败,则会抛出编译错误( compile-time error)。</li>
|
||||
<li>如果上述两个情况都不是(也就是说,编译器在编译时期无法确定转换能否成功,) 那么目标表达式就会变成指定的类型的optional. (is an optional of the specified type ) 然后在运行时,如果转换成功, 目标表达式就会作为 optional的一部分来返回, 否则,目标表达式返回nil. 对应的例子是: 把一个 superclass 转换成一个 subclass.</li>
|
||||
</ul>
|
||||
<pre><code class="lang-swift">class SomeSuperType {}
|
||||
class SomeType: SomeSuperType {}
|
||||
@ -802,22 +793,13 @@ let y2: SomeType = x // Type information from an annotation
|
||||
</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>
|
||||
<p>类型转换运算符(type-casting-operator)语法<br><em>类型转换运算符</em> → <strong>is</strong> <a href="..\chapter3\03_Types.html#type"><em>类型</em></a> | <strong>as</strong> <strong>?</strong> <em>可选</em> <a href="..\chapter3\03_Types.html#type"><em>类型</em></a> </p>
|
||||
</blockquote>
|
||||
<p><a name="primary_expressions"></a></p>
|
||||
<h2 id="-primary-expressions-">主要表达式(Primary Expressions)</h2>
|
||||
<p><code>主要表达式</code>是最基本的表达式。 它们可以跟 前缀表达式,二元表达式,后缀表达式以及其他主要表达式组合使用。</p>
|
||||
<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>
|
||||
<p>主表达式语法<br><em>主表达式</em> → <a href="LexicalStructure.html#identifier"><em>标识符</em></a> <a href="GenericParametersAndArguments.html#generic_argument_clause"><em>泛型参数子句</em></a> <em>可选</em><br><em>主表达式</em> → <a href="..\chapter3\04_Expressions.html#literal_expression"><em>字面量表达式</em></a><br><em>主表达式</em> → <a href="..\chapter3\04_Expressions.html#self_expression"><em>self表达式</em></a><br><em>主表达式</em> → <a href="..\chapter3\04_Expressions.html#superclass_expression"><em>超类表达式</em></a><br><em>主表达式</em> → <a href="..\chapter3\04_Expressions.html#closure_expression"><em>闭包表达式</em></a><br><em>主表达式</em> → <a href="..\chapter3\04_Expressions.html#parenthesized_expression"><em>圆括号表达式</em></a><br><em>主表达式</em> → <a href="..\chapter3\04_Expressions.html#implicit_member_expression"><em>隐式成员表达式</em></a><br><em>主表达式</em> → <a href="..\chapter3\04_Expressions.html#wildcard_expression"><em>通配符表达式</em></a> </p>
|
||||
</blockquote>
|
||||
<h3 id="-literal-expression-">字符型表达式(Literal Expression)</h3>
|
||||
<p>由这些内容组成:普通的字符(string, number) , 一个字符的字典或者数组,或者下面列表中的特殊字符。</p>
|
||||
@ -854,31 +836,22 @@ let y2: SomeType = x // Type information from an annotation
|
||||
</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>数组中的最后一个表达式可以紧跟一个逗号(','). []表示空数组 。 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 的最后一个表达式可以是一个逗号(','). [:] 表示一个空的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>
|
||||
<p>[<code>value 1</code>, <code>value 2</code>, <code>...</code>]</p>
|
||||
</blockquote>
|
||||
<p>数组中的最后一个表达式可以紧跟一个逗号(','). []表示空数组 。 array literal的type是 T[], 这个T就是数组中元素的type. 如果该数组中有多种type, T则是跟这些type的公共supertype最接近的type.(closest common supertype)</p>
|
||||
<p>一个<code>dictionary literal</code> 是一个包含无序的键值对(key-value pairs)的集合,它的形式是:</p>
|
||||
<blockquote>
|
||||
<p>[<code>key 1</code>: <code>value 1</code>, <code>key 2</code>: <code>value 2</code>, <code>...</code>]</p>
|
||||
</blockquote>
|
||||
<p>dictionary 的最后一个表达式可以是一个逗号(','). [:] 表示一个空的dictionary. 它的type是 Dictionary<KeyType, ValueType> (这里KeyType表示 key的type, ValueType表示 value的type) 如果这个dictionary 中包含多种 types, 那么KeyType, Value 则对应着它们的公共supertype最接近的type( closest common supertype).</p>
|
||||
<blockquote>
|
||||
<p>字面量表达式语法<br><em>字面量表达式</em> → <a href="LexicalStructure.html#literal"><em>字面量</em></a><br><em>字面量表达式</em> → <a href="..\chapter3\04_Expressions.html#array_literal"><em>数组字面量</em></a> | <a href="..\chapter3\04_Expressions.html#dictionary_literal"><em>字典字面量</em></a><br><em>字面量表达式</em> → <strong>__FILE__</strong> | <strong>__LINE__</strong> | <strong>__COLUMN__</strong> | <strong>__FUNCTION__</strong><br><em>数组字面量</em> → <strong>[</strong> <a href="..\chapter3\04_Expressions.html#array_literal_items"><em>数组字面量项列表</em></a> <em>可选</em> <strong>]</strong><br><em>数组字面量项列表</em> → <a href="..\chapter3\04_Expressions.html#array_literal_item"><em>数组字面量项</em></a> <strong>,</strong> <em>可选</em> | <a href="..\chapter3\04_Expressions.html#array_literal_item"><em>数组字面量项</em></a> <strong>,</strong> <a href="..\chapter3\04_Expressions.html#array_literal_items"><em>数组字面量项列表</em></a><br><em>数组字面量项</em> → <a href="..\chapter3\04_Expressions.html#expression"><em>表达式</em></a><br><em>字典字面量</em> → <strong>[</strong> <a href="..\chapter3\04_Expressions.html#dictionary_literal_items"><em>字典字面量项列表</em></a> <strong>]</strong> | <strong>[</strong> <strong>:</strong> <strong>]</strong><br><em>字典字面量项列表</em> → <a href="..\chapter3\04_Expressions.html#dictionary_literal_item"><em>字典字面量项</em></a> <strong>,</strong> <em>可选</em> | <a href="..\chapter3\04_Expressions.html#dictionary_literal_item"><em>字典字面量项</em></a> <strong>,</strong> <a href="..\chapter3\04_Expressions.html#dictionary_literal_items"><em>字典字面量项列表</em></a><br><em>字典字面量项</em> → <a href="..\chapter3\04_Expressions.html#expression"><em>表达式</em></a> <strong>:</strong> <a href="..\chapter3\04_Expressions.html#expression"><em>表达式</em></a> </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>
|
||||
<p>self<br>self.<code>member name</code><br>self[<code>subscript index</code>]<br>self(<code>initializer arguments</code>)<br>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 用来区分重名变量(例如函数的参数). 例如,
|
||||
@ -899,31 +872,23 @@ self.init(<code>initializer arguments</code>)</p>
|
||||
}
|
||||
</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>
|
||||
<p>Self 表达式语法<br><em>self表达式</em> → <strong>self</strong><br><em>self表达式</em> → <strong>self</strong> <strong>.</strong> <a href="LexicalStructure.html#identifier"><em>标识符</em></a><br><em>self表达式</em> → <strong>self</strong> <strong>[</strong> <a href="..\chapter3\04_Expressions.html#expression"><em>表达式</em></a> <strong>]</strong><br><em>self表达式</em> → <strong>self</strong> <strong>.</strong> <strong>init</strong> </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>
|
||||
<blockquote>
|
||||
<p>super.<code>member name</code><br>super[<code>subscript index</code>]<br>super.init(<code>initializer arguments</code>) </p>
|
||||
</blockquote>
|
||||
<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>
|
||||
<p>超类(superclass)表达式语法<br><em>超类表达式</em> → <a href="..\chapter3\04_Expressions.html#superclass_method_expression"><em>超类方法表达式</em></a> | <a href="..\chapter3\04_Expressions.html#超类下标表达式"><em>超类下标表达式</em></a> | <a href="..\chapter3\04_Expressions.html#superclass_initializer_expression"><em>超类构造器表达式</em></a><br><em>超类方法表达式</em> → <strong>super</strong> <strong>.</strong> <a href="LexicalStructure.html#identifier"><em>标识符</em></a><br><em>超类下标表达式</em> → <strong>super</strong> <strong>[</strong> <a href="..\chapter3\04_Expressions.html#expression"><em>表达式</em></a> <strong>]</strong><br><em>超类构造器表达式</em> → <strong>super</strong> <strong>.</strong> <strong>init</strong> </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) -> return type in
|
||||
<pre><code class="lang-swift">{ (parameters) -> return type in
|
||||
statements
|
||||
}
|
||||
}
|
||||
</code></pre>
|
||||
<p>闭包的参数声明形式跟方法中的声明一样, 请参见:Function Declaration.</p>
|
||||
<p>闭包还有几种特殊的形式, 让使用更加简洁:</p>
|
||||
@ -960,36 +925,28 @@ 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>
|
||||
<p>闭包表达式语法<br><em>闭包表达式</em> → <strong>{</strong> <a href="..\chapter3\04_Expressions.html#closure_signature"><em>闭包签名(Signational)</em></a> <em>可选</em> <a href="..\chapter3\10_Statements.html#statements"><em>多条语句(Statements)</em></a> <strong>}</strong><br><em>闭包签名(Signational)</em> → <a href="..\chapter3\05_Declarations.html#parameter_clause"><em>参数子句</em></a> <a href="..\chapter3\05_Declarations.html#function_result"><em>函数结果</em></a> <em>可选</em> <strong>in</strong><br><em>闭包签名(Signational)</em> → <a href="LexicalStructure.html#identifier_list"><em>标识符列表</em></a> <a href="..\chapter3\05_Declarations.html#function_result"><em>函数结果</em></a> <em>可选</em> <strong>in</strong><br><em>闭包签名(Signational)</em> → <a href="..\chapter3\04_Expressions.html#capture_list"><em>捕获(Capature)列表</em></a> <a href="..\chapter3\05_Declarations.html#parameter_clause"><em>参数子句</em></a> <a href="..\chapter3\05_Declarations.html#function_result"><em>函数结果</em></a> <em>可选</em> <strong>in</strong><br><em>闭包签名(Signational)</em> → <a href="..\chapter3\04_Expressions.html#capture_list"><em>捕获(Capature)列表</em></a> <a href="LexicalStructure.html#identifier_list"><em>标识符列表</em></a> <a href="..\chapter3\05_Declarations.html#function_result"><em>函数结果</em></a> <em>可选</em> <strong>in</strong><br><em>闭包签名(Signational)</em> → <a href="..\chapter3\04_Expressions.html#capture_list"><em>捕获(Capature)列表</em></a> <strong>in</strong><br><em>捕获(Capature)列表</em> → <strong>[</strong> <a href="..\chapter3\04_Expressions.html#capture_specifier"><em>捕获(Capature)说明符</em></a> <a href="..\chapter3\04_Expressions.html#expression"><em>表达式</em></a> <strong>]</strong><br><em>捕获(Capature)说明符</em> → <strong>weak</strong> | <strong>unowned</strong> | <strong>unowned(safe)</strong> | <strong>unowned(unsafe)</strong> </p>
|
||||
</blockquote>
|
||||
<h3 id="-implicit-member-expression-">隐式成员表达式(Implicit Member Expression)</h3>
|
||||
<p>在可以判断出类型(type)的上下文(context)中,隐式成员表达式是访问某个type的member( 例如 class method, enumeration case) 的简洁方法。 它的形式是:</p>
|
||||
<blockquote>
|
||||
<p>.<code>member name</code></p>
|
||||
</blockquote>
|
||||
<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>
|
||||
<p>隐式成员表达式语法<br><em>隐式成员表达式</em> → <strong>.</strong> <a href="..\chapter3\02_Lexical_Structure.html#identifier"><em>标识符</em></a> </p>
|
||||
</blockquote>
|
||||
<h3 id="-parenthesized-expression-">圆括号表达式(Parenthesized Expression)</h3>
|
||||
<p>圆括号表达式由多个子表达式和逗号','组成。 每个子表达式前面可以有 identifier x: 这样的可选前缀。形式如下:</p>
|
||||
<blockquote>
|
||||
<p>(<code>identifier 1</code>: <code>expression 1</code>, <code>identifier 2</code>: <code>expression 2</code>, <code>...</code>)</p>
|
||||
</blockquote>
|
||||
<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>
|
||||
<p>圆括号表达式(Parenthesized Expression)语法<br><em>圆括号表达式</em> → <strong>(</strong> <a href="..\chapter3\04_Expressions.html#expression_element_list"><em>表达式元素列表</em></a> <em>可选</em> <strong>)</strong><br><em>表达式元素列表</em> → <a href="..\chapter3\04_Expressions.html#expression_element"><em>表达式元素</em></a> | <a href="..\chapter3\04_Expressions.html#expression_element"><em>表达式元素</em></a> <strong>,</strong> <a href="..\chapter3\04_Expressions.html#expression_element_list"><em>表达式元素列表</em></a><br><em>表达式元素</em> → <a href="..\chapter3\04_Expressions.html#expression"><em>表达式</em></a> | <a href="..\chapter3\02_Lexical_Structure.html#identifier"><em>标识符</em></a> <strong>:</strong> <a href="..\chapter3\04_Expressions.html#expression"><em>表达式</em></a> </p>
|
||||
</blockquote>
|
||||
<h3 id="-wildcard-expression-">通配符表达式(Wildcard Expression)</h3>
|
||||
<p>通配符表达式用来忽略传递进来的某个参数。例如:下面的代码中,10被传递给x, 20被忽略(译注:好奇葩的语法。。。)</p>
|
||||
@ -997,8 +954,7 @@ x = .AnotherValue
|
||||
// x is 10, 20 is ignored
|
||||
</code></pre>
|
||||
<blockquote>
|
||||
<p>通配符表达式的语法</p>
|
||||
<p><em>wildcard-expression</em> → _</p>
|
||||
<p>通配符表达式语法<br><em>通配符表达式</em> → <strong>_</strong> </p>
|
||||
</blockquote>
|
||||
<p><a name="postfix_expressions"></a></p>
|
||||
<h2 id="-postfix-expressions-">后缀表达式(Postfix Expressions)</h2>
|
||||
@ -1010,25 +966,19 @@ x = .AnotherValue
|
||||
</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>
|
||||
<p>后置表达式语法<br><em>后置表达式</em> → <a href="..\chapter3\04_Expressions.html#primary_expression"><em>主表达式</em></a><br><em>后置表达式</em> → <a href="..\chapter3\04_Expressions.html#postfix_expression"><em>后置表达式</em></a> <a href="..\chapter3\02_Lexical_Structure.html#postfix_operator"><em>后置运算符</em></a><br><em>后置表达式</em> → <a href="..\chapter3\04_Expressions.html#function_call_expression"><em>函数调用表达式</em></a><br><em>后置表达式</em> → <a href="..\chapter3\04_Expressions.html#initializer_expression"><em>构造器表达式</em></a><br><em>后置表达式</em> → <a href="..\chapter3\04_Expressions.html#explicit_member_expression"><em>显示成员表达式</em></a><br><em>后置表达式</em> → <a href="..\chapter3\04_Expressions.html#postfix_self_expression"><em>后置self表达式</em></a><br><em>后置表达式</em> → <a href="..\chapter3\04_Expressions.html#dynamic_type_expression"><em>动态类型表达式</em></a><br><em>后置表达式</em> → <a href="..\chapter3\04_Expressions.html#subscript_expression"><em>下标表达式</em></a><br><em>后置表达式</em> → <a href="..\chapter3\04_Expressions.html#forced_value_expression"><em>强制取值(Forced Value)表达式</em></a><br><em>后置表达式</em> → <a href="..\chapter3\04_Expressions.html#optional_chaining_expression"><em>可选链(Optional Chaining)表达式</em></a> </p>
|
||||
</blockquote>
|
||||
<h3 id="-function-call-expression-">函数调用表达式(Function Call Expression)</h3>
|
||||
<p>函数调用表达式由函数名和参数列表组成。它的形式如下:</p>
|
||||
<blockquote>
|
||||
<p><code>function name</code>(<code>argument value 1</code>, <code>argument value 2</code>)</p>
|
||||
</blockquote>
|
||||
<p>The function name can be any expression whose value is of a function type.
|
||||
(不用翻译了, 太罗嗦)</p>
|
||||
<p>如果该function 的声明中指定了参数的名字,那么在调用的时候也必须得写出来. 例如:</p>
|
||||
<blockquote>
|
||||
<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>
|
||||
</blockquote>
|
||||
<p>可以在 函数调用表达式的尾部(最后一个参数之后)加上 一个闭包(closure) , 该闭包会被目标函数理解并执行。它具有如下两种写法:</p>
|
||||
<pre><code class="lang-swift">// someFunction takes an integer and a closure as its arguments
|
||||
someFunction(x, {$0 == 13})
|
||||
@ -1040,23 +990,19 @@ 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>
|
||||
<p>函数调用表达式语法<br><em>函数调用表达式</em> → <a href="..\chapter3\04_Expressions.html#postfix_expression"><em>后置表达式</em></a> <a href="..\chapter3\04_Expressions.html#parenthesized_expression"><em>圆括号表达式</em></a><br><em>函数调用表达式</em> → <a href="..\chapter3\04_Expressions.html#postfix_expression"><em>后置表达式</em></a> <a href="..\chapter3\04_Expressions.html#parenthesized_expression"><em>圆括号表达式</em></a> <em>可选</em> <a href="..\chapter3\04_Expressions.html#trailing_closure"><em>后置闭包(Trailing Closure)</em></a><br><em>后置闭包(Trailing Closure)</em> → <a href="..\chapter3\04_Expressions.html#closure_expression"><em>闭包表达式</em></a> </p>
|
||||
</blockquote>
|
||||
<h3 id="-initializer-expression-">初始化函数表达式(Initializer Expression)</h3>
|
||||
<p>Initializer表达式用来给某个Type初始化。 它的形式如下:</p>
|
||||
<blockquote>
|
||||
<p><code>expression</code>.init(<code>initializer arguments</code>)</p>
|
||||
</blockquote>
|
||||
<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 {
|
||||
</code></pre>
|
||||
<p>可以通过 initializer 表达式来委托调用(delegate to )到superclass的initializers.</p>
|
||||
<pre><code class="lang-swift">class SomeSubClass: SomeSuperClass {
|
||||
init() {
|
||||
// subclass initialization goes here
|
||||
super.init()
|
||||
@ -1064,12 +1010,13 @@ class SomeSubClass: SomeSuperClass {
|
||||
}
|
||||
</code></pre>
|
||||
<blockquote>
|
||||
<p>initializer表达式的语法</p>
|
||||
<p><em>initializer-expression</em> → <em>postfix-expression</em>.init</p>
|
||||
<p>构造器表达式语法<br><em>构造器表达式</em> → <a href="..\chapter3\04_Expressions.html#postfix_expression"><em>后置表达式</em></a> <strong>.</strong> <strong>init</strong> </p>
|
||||
</blockquote>
|
||||
<h3 id="-explicit-member-expression-">显式成员表达式(Explicit Member Expression)</h3>
|
||||
<p>显示成员表达式允许我们访问type, tuple, module的成员变量。它的形式如下:</p>
|
||||
<blockquote>
|
||||
<p><code>expression</code>.<code>member name</code></p>
|
||||
</blockquote>
|
||||
<p>该member 就是某个type在声明时候所定义(declaration or extension) 的变量, 例如:</p>
|
||||
<pre><code class="lang-swift">class SomeClass {
|
||||
var someProperty = 42
|
||||
@ -1085,24 +1032,24 @@ t.0 = t.1
|
||||
<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>
|
||||
<p>显式成员表达式语法<br><em>显示成员表达式</em> → <a href="..\chapter3\04_Expressions.html#postfix_expression"><em>后置表达式</em></a> <strong>.</strong> <a href="..\chapter3\02_Lexical_Structure.html#decimal_digit"><em>十进制数字</em></a><br><em>显示成员表达式</em> → <a href="..\chapter3\04_Expressions.html#postfix_expression"><em>后置表达式</em></a> <strong>.</strong> <a href="..\chapter3\02_Lexical_Structure.html#identifier"><em>标识符</em></a> <a href="GenericParametersAndArguments.html#generic_argument_clause"><em>泛型参数子句</em></a> <em>可选</em> </p>
|
||||
</blockquote>
|
||||
<h3 id="-self-postfix-self-expression-">后缀self表达式(Postfix Self Expression)</h3>
|
||||
<p>后缀表达式由 某个表达式 + '.self' 组成. 形式如下:</p>
|
||||
<p><code>expression</code>.self
|
||||
<code>type</code>.self</p>
|
||||
<blockquote>
|
||||
<p><code>expression</code>.self<br><code>type</code>.self </p>
|
||||
</blockquote>
|
||||
<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>
|
||||
<p>后置Self 表达式语法<br><em>后置self表达式</em> → <a href="..\chapter3\04_Expressions.html#postfix_expression"><em>后置表达式</em></a> <strong>.</strong> <strong>self</strong> </p>
|
||||
</blockquote>
|
||||
<h3 id="dynamic-dynamic-type-expression-">dynamic表达式(Dynamic Type Expression)</h3>
|
||||
<p>(因为dynamicType是一个独有的方法,所以这里保留了英文单词,未作翻译, --- 类似与self expression)</p>
|
||||
<p>dynamicType 表达式由 某个表达式 + '.dynamicType' 组成。</p>
|
||||
<blockquote>
|
||||
<p><code>expression</code>.dynamicType</p>
|
||||
</blockquote>
|
||||
<p>上面的形式中, expression 不能是某type的名字(当然了,如果我都知道它的名字了还需要动态来获取它吗)。动态类型表达式会返回"运行时"某个instance的type, 具体请看下面的列子:</p>
|
||||
<pre><code class="lang-swift">class SomeBaseClass {
|
||||
class func printClassName() {
|
||||
@ -1122,29 +1069,32 @@ someInstance.dynamicType.printClassName()
|
||||
// prints "SomeSubClass"
|
||||
</code></pre>
|
||||
<blockquote>
|
||||
<p>dynamic type 表达式</p>
|
||||
<p><em>dynamic-type-expression</em> → <em>postfix-expression</em>.dynamicType</p>
|
||||
<p>动态类型表达式语法<br><em>动态类型表达式</em> → <a href="..\chapter3\04_Expressions.html#postfix_expression"><em>后置表达式</em></a> <strong>.</strong> <strong>dynamicType</strong> </p>
|
||||
</blockquote>
|
||||
<h3 id="-subscript-expression-">下标脚本表达式(Subscript Expression)</h3>
|
||||
<p>下标脚本表达式提供了通过下标脚本访问getter/setter 的方法。它的形式是:</p>
|
||||
<blockquote>
|
||||
<p><code>expression</code>[<code>index expressions</code>]</p>
|
||||
</blockquote>
|
||||
<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>
|
||||
<p>附属脚本表达式语法<br><em>附属脚本表达式</em> → <a href="..\chapter3\04_Expressions.html#postfix_expression"><em>后置表达式</em></a> <strong>[</strong> <a href="..\chapter3\04_Expressions.html#expression_list"><em>表达式列表</em></a> <strong>]</strong> </p>
|
||||
</blockquote>
|
||||
<h3 id="-forced-value-expression-">强制取值表达式(Forced-Value Expression)</h3>
|
||||
<p>强制取值表达式用来获取某个目标表达式的值(该目标表达式的值必须不是nil )。它的形式如下:</p>
|
||||
<blockquote>
|
||||
<p><code>expression</code>!</p>
|
||||
</blockquote>
|
||||
<p>如果该表达式的值不是nil, 则返回对应的值。 否则,抛出运行时错误(runtime error)。</p>
|
||||
<blockquote>
|
||||
<p>强制取值表达式的语法</p>
|
||||
<p><em>forced-value-expression</em> → <em>postfix-expression</em>!</p>
|
||||
<p>强制取值(Forced Value)语法<br><em>强制取值(Forced Value)表达式</em> → <a href="..\chapter3\04_Expressions.html#postfix_expression"><em>后置表达式</em></a> <strong>!</strong> </p>
|
||||
</blockquote>
|
||||
<h3 id="-optional-chaining-expression-">可选链表达式(Optional-Chaining Expression)</h3>
|
||||
<p>可选链表达式由目标表达式 + '?' 组成,形式如下:</p>
|
||||
<blockquote>
|
||||
<p><code>expression</code>?</p>
|
||||
</blockquote>
|
||||
<p>后缀'?' 返回目标表达式的值,把它做为可选的参数传递给后续的表达式</p>
|
||||
<p>如果某个后缀表达式包含了可选链表达式,那么它的执行过程就比较特殊: 首先先判断该可选链表达式的值,如果是 nil, 整个后缀表达式都返回 nil, 如果该可选链的值不是nil, 则正常返回该后缀表达式的值(依次执行它的各个子表达式)。在这两种情况下,该后缀表达式仍然是一个optional type(In either case, the value of the postfix expression is still of an optional type)</p>
|
||||
<p>如果某个"后缀表达式"的"子表达式"中包含了"可选链表达式",那么只有最外层的表达式返回的才是一个optional type. 例如,在下面的例子中, 如果c 不是nil, 那么 c?.property.performAction() 这句代码在执行时,就会先获得c 的property方法,然后调用 performAction()方法。 然后对于 "c?.property.performAction()" 这个整体,它的返回值是一个optional type.</p>
|
||||
@ -1157,8 +1107,7 @@ var result: Bool? = c?.property.performAction()
|
||||
}
|
||||
</code></pre>
|
||||
<blockquote>
|
||||
<p>可选链表达式的语法</p>
|
||||
<p><em>optional-chaining-expression</em> → <em>postfix-expression</em>?</p>
|
||||
<p>可选链表达式语法<br><em>可选链表达式</em> → <a href="..\chapter3\04_Expressions.html#postfix_expression"><em>后置表达式</em></a> <strong>?</strong> </p>
|
||||
</blockquote>
|
||||
|
||||
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="3.6" data-basepath=".." data-revision="1402750255397">
|
||||
<div class="book" data-level="3.6" data-basepath=".." data-revision="1402759431779">
|
||||
<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,11 +587,10 @@
|
||||
|
||||
<div class="page-inner">
|
||||
|
||||
<section class="normal" id="section-gitbook_91">
|
||||
<section class="normal" id="section-gitbook_565">
|
||||
|
||||
<blockquote>
|
||||
<p>翻译:marsprince</p>
|
||||
<p>校对:numbbbbb, stanzhai</p>
|
||||
<p>翻译:marsprince<br>校对:numbbbbb, stanzhai </p>
|
||||
</blockquote>
|
||||
<h1 id="-">声明</h1>
|
||||
<hr>
|
||||
@ -632,10 +631,10 @@
|
||||
<p><a name="code_blocks"></a></p>
|
||||
<h2 id="-">代码块</h2>
|
||||
<p>代码块用来将一些声明和控制结构的语句组织在一起。它有如下的形式:</p>
|
||||
<pre><code>{
|
||||
`statements`
|
||||
}
|
||||
</code></pre><p>代码块中的语句包括声明,表达式和各种其他类型的语句,它们按照在源码中的出现顺序被依次执行。</p>
|
||||
<blockquote>
|
||||
<p>{<br> <code>statements</code><br>} </p>
|
||||
</blockquote>
|
||||
<p>代码块中的语句包括声明,表达式和各种其他类型的语句,它们按照在源码中的出现顺序被依次执行。</p>
|
||||
<blockquote>
|
||||
<p>代码块语法<br><em>代码块</em> → <strong>{</strong> <a href="..\chapter3\10_Statements.html#statements"><em>多条语句(Statements)</em></a> <em>可选</em> <strong>}</strong> </p>
|
||||
</blockquote>
|
||||
@ -643,30 +642,39 @@
|
||||
<h2 id="-">引入声明</h2>
|
||||
<p>引入声明使你可以使用在其他文件中声明的内容。引入语句的基本形式是引入整个代码模块;它由import关键字开始,后面
|
||||
紧跟一个模块名:</p>
|
||||
<pre><code>import module
|
||||
</code></pre><p>你可以提供更多的细节来限制引入的符号,如声明一个特殊的子模块或者在一个模块或子模块中做特殊的声明。(待改进)
|
||||
<blockquote>
|
||||
<p>import <code>module</code></p>
|
||||
</blockquote>
|
||||
<p>你可以提供更多的细节来限制引入的符号,如声明一个特殊的子模块或者在一个模块或子模块中做特殊的声明。(待改进)
|
||||
当你使用了这些细节后,在当前的程序汇总只有引入的符号是可用的(并不是声明的整个模块)。</p>
|
||||
<pre><code>import import kind module.symbol name
|
||||
import module.submodule
|
||||
</code></pre><blockquote>
|
||||
<blockquote>
|
||||
<p>import <code>import kind</code> <code>module</code>.<code>symbol name</code><br>import <code>module</code>.<code>submodule</code> </p>
|
||||
</blockquote>
|
||||
<p></p>
|
||||
|
||||
<blockquote>
|
||||
<p>导入(Import)声明语法<br><em>导入声明</em> → <a href="..\chapter3\06_Attributes.html#attributes"><em>特性(Attributes)列表</em></a> <em>可选</em> <strong>import</strong> <a href="..\chapter3\05_Declarations.html#import_kind"><em>导入类型</em></a> <em>可选</em> <a href="..\chapter3\05_Declarations.html#import_path"><em>导入路径</em></a><br><em>导入类型</em> → <strong>typealias</strong> | <strong>struct</strong> | <strong>class</strong> | <strong>enum</strong> | <strong>protocol</strong> | <strong>var</strong> | <strong>func</strong><br><em>导入路径</em> → <a href="..\chapter3\05_Declarations.html#import_path_identifier"><em>导入路径标识符</em></a> | <a href="..\chapter3\05_Declarations.html#import_path_identifier"><em>导入路径标识符</em></a> <strong>.</strong> <a href="..\chapter3\05_Declarations.html#import_path"><em>导入路径</em></a><br><em>导入路径标识符</em> → <a href="LexicalStructure.html#identifier"><em>标识符</em></a> | <a href="LexicalStructure.html#operator"><em>运算符</em></a> </p>
|
||||
</blockquote>
|
||||
<p><a name="constant_declaration"></a></p>
|
||||
<h2 id="-">常量声明</h2>
|
||||
<p>常量声明可以在你的程序里命名一个常量。常量以关键词let来声明,遵循如下的格式:</p>
|
||||
<pre><code>let constant name: type = expression
|
||||
</code></pre><p>当常量的值被给定后,常量就将常量名称和表达式初始值不变的结合在了一起,而且不能更改。
|
||||
<blockquote>
|
||||
<p>let <code>constant name</code>: <code>type</code> = <code>expression</code></p>
|
||||
</blockquote>
|
||||
<p>当常量的值被给定后,常量就将常量名称和表达式初始值不变的结合在了一起,而且不能更改。
|
||||
这意味着如果常量以类的形式被初始化,类本身的内容是可以改变的,但是常量和类之间的结合关系是不能改变的。
|
||||
当一个常量被声明为全局变量,它必须被给定一个初始值。当一个常量在类或者结构体中被声明时,它被认为是一个常量
|
||||
属性。常量并不是可计算的属性,因此不包含getters和setters。(译者注:getters和setters不知道怎么翻译,待改进)</p>
|
||||
<p>如果常量名是一个元祖形式,元祖中的每一项初始化表达式中都要有对应的值</p>
|
||||
<pre><code>let (firstNumber, secondNumber) = (10, 42)
|
||||
</code></pre><p>在上例中,firstNumber是一个值为10的常量,secnodeName是一个值为42的常量。所有常量都可以独立的使用:</p>
|
||||
<pre><code>println("The first number is \(firstNumber).")
|
||||
<pre><code class="lang-swift">let (firstNumber, secondNumber) = (10, 42)
|
||||
</code></pre>
|
||||
<p>在上例中,firstNumber是一个值为10的常量,secnodeName是一个值为42的常量。所有常量都可以独立的使用:</p>
|
||||
<pre><code class="lang-swift">println("The first number is \(firstNumber).")
|
||||
// prints "The first number is 10."
|
||||
println("The second number is \(secondNumber).")
|
||||
// prints "The second number is 42."
|
||||
</code></pre><p>类型注释(:type)在常量声明中是一个可选项,它可以用来描述在类型推断(type inference)中找到的类型。</p>
|
||||
</code></pre>
|
||||
<p>类型注释(:type)在常量声明中是一个可选项,它可以用来描述在类型推断(type inference)中找到的类型。</p>
|
||||
<p>声明一个静态常量要使用关键字static。静态属性在类型属性(type propetries)中有介绍。</p>
|
||||
<p>如果还想获得更多关于常量的信息或者想在使用中获得帮助,请查看常量和变量(constants and variables),
|
||||
存储属性(stored properties)等节。</p>
|
||||
@ -679,28 +687,24 @@ println("The second number is \(secondNumber).")
|
||||
变量和属性,存储变量和属性监视,和静态变量属性,有着不同的声明形式。(待改进)
|
||||
所使用的声明形式取决于变量所声明的范围和你打算声明的变量类型。</p>
|
||||
<blockquote>
|
||||
<p>注意:</p>
|
||||
<p>你也可以在协议声明的上下文声明属性,详情参见类型属性声明。</p>
|
||||
<p>注意:<br>你也可以在协议声明的上下文声明属性,详情参见类型属性声明。</p>
|
||||
</blockquote>
|
||||
<h3 id="-">存储型变量和存储型属性</h3>
|
||||
<p>下面的形式声明了一个存储型变量或存储型变量属性</p>
|
||||
<pre><code>var variable name: type = expression
|
||||
</code></pre><p>你可以在全局,函数内,或者在类和结构体的声明(context)中使用这种形式来声明一个变量。当变量以这种形式
|
||||
<blockquote>
|
||||
<p>var <code>variable name</code>: <code>type</code> = <code>expression</code></p>
|
||||
</blockquote>
|
||||
<p>你可以在全局,函数内,或者在类和结构体的声明(context)中使用这种形式来声明一个变量。当变量以这种形式
|
||||
在全局或者一个函数内被声明时,它代表一个存储型变量。当它在类或者结构体中被声明时,它代表一个存储型变量属性。</p>
|
||||
<p>构造器表达式可以被</p>
|
||||
<p>和常量声明相比,如果变量名是一个元祖类型,元祖的每一项的名字都要和初始化表达式一致。</p>
|
||||
<p>正如名字一样,存储型变量的值或存储型变量属性存储在内存中。</p>
|
||||
<h3 id="-">计算型变量和计算型属性</h3>
|
||||
<p>如下形式声明一个一个存储型变量或存储型属性:</p>
|
||||
<pre><code>var variable name: type {
|
||||
get {
|
||||
statements
|
||||
}
|
||||
set(setter name) {
|
||||
statements
|
||||
}
|
||||
}
|
||||
</code></pre><p>你可以在全局,函数体内或者类,结构体,枚举,扩展声明的上下文中使用这种形式的声明。
|
||||
<blockquote>
|
||||
<p>var <code>variable name</code>: <code>type</code> {<br>get {<br> <code>statements</code><br>}<br>set(<code>setter name</code>) {<br> <code>statements</code><br>}<br>} </p>
|
||||
</blockquote>
|
||||
<p>你可以在全局,函数体内或者类,结构体,枚举,扩展声明的上下文中使用这种形式的声明。
|
||||
当变量以这种形式在全局或者一个函数内被声明时,它代表一个计算型变量。当它在类,结构体,枚举,扩展声明的上下文
|
||||
中中被声明时,它代表一个计算型变量属性。</p>
|
||||
<p>getter用来读取变量值,setter用来写入变量值。setter子句是可选择的,只有getter是必需的,你可以将这些语句
|
||||
@ -712,15 +716,10 @@ setter的初始名为newValue,正如在seter声明速记(shorthand setter decl
|
||||
<p>获得更多信息,查看更多关于计算型属性的例子,请查看计算型属性(computed properties)一节。</p>
|
||||
<h3 id="-">存储型变量监视器和属性监视器</h3>
|
||||
<p>你可以用willset和didset监视器来声明一个存储型变量或属性。一个包含监视器的存储型变量或属性按如下的形式声明:</p>
|
||||
<pre><code>var variable name: type = expression {
|
||||
willSet(setter name) {
|
||||
statements
|
||||
}
|
||||
didSet(setter name {
|
||||
statements
|
||||
}
|
||||
}
|
||||
</code></pre><p>你可以在全局,函数体内或者类,结构体,枚举,扩展声明的上下文中使用这种形式的声明。
|
||||
<blockquote>
|
||||
<p>var <code>variable name</code>: <code>type</code> = expression {<br>willSet(setter name) {<br> <code>statements</code><br>}<br>didSet(<code>setter name</code>) {<br> <code>statements</code><br>}<br>} </p>
|
||||
</blockquote>
|
||||
<p>你可以在全局,函数体内或者类,结构体,枚举,扩展声明的上下文中使用这种形式的声明。
|
||||
当变量以这种形式在全局或者一个函数内被声明时,监视器代表一个存储型变量监视器;
|
||||
当它在类,结构体,枚举,扩展声明的上下文中被声明时,监视器代表属性监视器。</p>
|
||||
<p>你可以为适合的监视器添加任何存储型属性。你也可以通过重写子类属性的方式为适合的监视器添加任何继承的属性
|
||||
@ -746,8 +745,10 @@ willset监视器初始名为newvalue,didset监视器初始名为oldvalue。</p
|
||||
<h2 id="-">类型的别名声明</h2>
|
||||
<p>类型别名的声明可以在你的程序里为一个已存在的类型声明一个别名。类型的别名声明以关键字typealias开始,遵循如下的
|
||||
形式:</p>
|
||||
<pre><code>typealias name = existing type
|
||||
</code></pre><p>当一个类型被别名被声明后,你可以在你程序的任何地方使用别名来代替已存在的类型。已存在的类型可以是已经被命名的
|
||||
<blockquote>
|
||||
<p><code>typealias name</code> = <code>existing type</code></p>
|
||||
</blockquote>
|
||||
<p>当一个类型被别名被声明后,你可以在你程序的任何地方使用别名来代替已存在的类型。已存在的类型可以是已经被命名的
|
||||
类型或者是混合类型。类型的别名不产生新的类型,它只是简单的和已存在的类型做名称替换。</p>
|
||||
<p>查看更多Protocol Associated Type Declaration.</p>
|
||||
<blockquote>
|
||||
@ -757,14 +758,14 @@ willset监视器初始名为newvalue,didset监视器初始名为oldvalue。</p
|
||||
<h2 id="-">函数声明</h2>
|
||||
<p>你可以使用函数声明在你的程序里引入新的函数。函数可以在类的上下文,结构体,枚举,或者作为方法的协议中被声明。
|
||||
函数声明使用关键字func,遵循如下的形式:</p>
|
||||
<pre><code>func function name(parameters) -> return type {
|
||||
statements
|
||||
}
|
||||
</code></pre><p>如果函数不返回任何值,返回类型可以被忽略,如下所示:</p>
|
||||
<pre><code>func function name(parameters) {
|
||||
statements
|
||||
}
|
||||
</code></pre><p>每个参数的类型都要标明,它们不能被推断出来。初始时函数的参数是常值。在这些参数前面添加var使它们成为变量,
|
||||
<blockquote>
|
||||
<p>func <code>function name</code>(<code>parameters</code>) -> <code>return type</code> {<br> <code>statements</code><br>} </p>
|
||||
</blockquote>
|
||||
<p>如果函数不返回任何值,返回类型可以被忽略,如下所示:</p>
|
||||
<blockquote>
|
||||
<p>func <code>function name</code>(<code>parameters</code>) {<br> <code>statements</code><br>} </p>
|
||||
</blockquote>
|
||||
<p>每个参数的类型都要标明,它们不能被推断出来。初始时函数的参数是常值。在这些参数前面添加var使它们成为变量,
|
||||
作用域内任何对变量的改变只在函数体内有效,或者用inout使的这些改变可以在调用域内生效。
|
||||
更多关于in-out参数的讨论,参见in-out参数(in-out parameters)</p>
|
||||
<p>函数可以使用元组类型作为返回值来返回多个变量。</p>
|
||||
@ -772,36 +773,39 @@ willset监视器初始名为newvalue,didset监视器初始名为oldvalue。</p
|
||||
<h3 id="-">参数名</h3>
|
||||
<p>函数的参数是一个以逗号分隔的列表 。函数调用是的变量顺序必须和函数声明时的参数顺序一致。
|
||||
最简单的参数列表有着如下的形式:</p>
|
||||
<pre><code>parameter name: parameter type
|
||||
</code></pre><p>对于函数参数来讲,参数名在函数体内被使用,而不是在函数调用时使用。对于方法参数,参数名在函数体内被使用,
|
||||
<blockquote>
|
||||
<p><code>parameter name</code>: <code>parameter type</code></p>
|
||||
</blockquote>
|
||||
<p>对于函数参数来讲,参数名在函数体内被使用,而不是在函数调用时使用。对于方法参数,参数名在函数体内被使用,
|
||||
同时也在方法被调用时作为标签被使用。该方法的第一个参数名仅仅在函数体内被使用,就像函数的参数一样,举例来讲:</p>
|
||||
<pre><code>func f(x: Int, y: String) -> String {
|
||||
<pre><code class="lang-swift">func f(x: Int, y: String) -> String {
|
||||
return y + String(x)
|
||||
}
|
||||
f(7, "hello") // x and y have no name
|
||||
|
||||
class C {
|
||||
</code></pre>
|
||||
<pre><code class="lang-swift">class C {
|
||||
func f(x: Int, y: String) -> String {
|
||||
return y + String(x)
|
||||
}
|
||||
}
|
||||
let c = C()
|
||||
c.f(7, y: "hello") // x没有名称,y有名称
|
||||
</code></pre><p>你可以按如下的形式,重写参数名被使用的过程:</p>
|
||||
<pre><code>external parameter name local parameter name: parameter type
|
||||
#parameter name: parameter type
|
||||
_ local parameter name: parameter type
|
||||
</code></pre><p>在本地参数前命名的第二名称(second name)使得参数有一个扩展名。且不同于本地的参数名。
|
||||
</code></pre>
|
||||
<p>你可以按如下的形式,重写参数名被使用的过程:</p>
|
||||
<blockquote>
|
||||
<p><code>external parameter name</code> <code>local parameter name</code>: <code>parameter type</code><br>#<code>parameter name</code>: <code>parameter type</code><br>_ <code>local parameter name</code>: <code>parameter type</code> </p>
|
||||
</blockquote>
|
||||
<p>在本地参数前命名的第二名称(second name)使得参数有一个扩展名。且不同于本地的参数名。
|
||||
扩展参数名在函数被调用时必须被使用。对应的参数在方法或函数被调用时必须有扩展名 。</p>
|
||||
<p>在参数名前所写的哈希符号(#)代表着这个参数名可以同时作为外部或本体参数名来使用。等同于书写两次本地参数名。
|
||||
在函数或方法调用时,与其对应的语句必须包含这个名字。</p>
|
||||
<p>本地参数名前的强调字符(_)使参数在函数被调用时没有名称。在函数或方法调用时,与其对应的语句必须没有名字。</p>
|
||||
<h3 id="-">特殊类型的参数</h3>
|
||||
<p>参数可以被忽略,值可以是变化的,并且提供一个初始值,这种方法有着如下的形式:</p>
|
||||
<pre><code>_ : <#parameter type#.
|
||||
parameter name: parameter type...
|
||||
parameter name: parameter type = default argument value
|
||||
</code></pre><p>以强调符(_)命名的参数明确的在函数体内不能被访问。</p>
|
||||
<blockquote>
|
||||
<p>_ : <#parameter type#.<br><code>parameter name</code>: <code>parameter type</code>...<br><code>parameter name</code>: <code>parameter type</code> = <code>default argument value</code> </p>
|
||||
</blockquote>
|
||||
<p>以强调符(_)命名的参数明确的在函数体内不能被访问。</p>
|
||||
<p>一个以基础类型名的参数,如果紧跟着三个点(...),被理解为是可变参数。一个函数至多可以拥有一个可变参数,
|
||||
且必须是最后一个参数。可变参数被作为该基本类型名的数组来看待。举例来讲,可变参数int...被看做是int[]。
|
||||
查看可变参数的使用例子,详见可变参数(variadic parameters)一节。</p>
|
||||
@ -815,11 +819,11 @@ f()和f(x:7)都是只有一个变量x的函数的有效调用,但是f(7)是非
|
||||
<p>和类型相关而不是和类型实例相关的方法必须在static声明的结构以或枚举内,亦或是以class关键字定义的类内。</p>
|
||||
<h3 id="-">柯里化函数和方法</h3>
|
||||
<p>柯里化函数或方法有着如下的形式:</p>
|
||||
<pre><code>func function name(parameters)(parameters) -> return type {
|
||||
statements
|
||||
}
|
||||
</code></pre><p>以这种形式定义的函数的返回值是另一个函数。举例来说,下面的两个声明时等价的:</p>
|
||||
<pre><code>func addTwoNumbers(a: Int)(b: Int) -> Int {
|
||||
<blockquote>
|
||||
<p>func <code>function name</code>(<code>parameters</code>)(<code>parameters</code>) -> <code>return type</code> {<br> <code>statements</code><br>} </p>
|
||||
</blockquote>
|
||||
<p>以这种形式定义的函数的返回值是另一个函数。举例来说,下面的两个声明时等价的:</p>
|
||||
<pre><code class="lang-swift">func addTwoNumbers(a: Int)(b: Int) -> Int {
|
||||
return a + b
|
||||
}
|
||||
func addTwoNumbers(a: Int) -> (Int -> Int) {
|
||||
@ -828,9 +832,10 @@ func addTwoNumbers(a: Int) -> (Int -> Int) {
|
||||
}
|
||||
return addTheSecondNumber
|
||||
}
|
||||
|
||||
addTwoNumbers(4)(5) // Returns 9
|
||||
</code></pre><p>多级柯里化应用如下</p>
|
||||
</code></pre>
|
||||
<pre><code class="lang-swift">addTwoNumbers(4)(5) // Returns 9
|
||||
</code></pre>
|
||||
<p>多级柯里化应用如下</p>
|
||||
<blockquote>
|
||||
<p>函数声明语法<br><em>函数声明</em> → <a href="..\chapter3\05_Declarations.html#function_head"><em>函数头</em></a> <a href="..\chapter3\05_Declarations.html#function_name"><em>函数名</em></a> <a href="GenericParametersAndArguments.html#generic_parameter_clause"><em>泛型参数子句</em></a> <em>可选</em> <a href="..\chapter3\05_Declarations.html#function_signature"><em>函数签名(Signature)</em></a> <a href="..\chapter3\05_Declarations.html#function_body"><em>函数体</em></a><br><em>函数头</em> → <a href="..\chapter3\06_Attributes.html#attributes"><em>特性(Attributes)列表</em></a> <em>可选</em> <a href="..\chapter3\05_Declarations.html#declaration_specifiers"><em>声明描述符(Specifiers)列表</em></a> <em>可选</em> <strong>func</strong><br><em>函数名</em> → <a href="LexicalStructure.html#identifier"><em>标识符</em></a> | <a href="LexicalStructure.html#operator"><em>运算符</em></a><br><em>函数签名(Signature)</em> → <a href="..\chapter3\05_Declarations.html#parameter_clauses"><em>parameter-clauses</em></a> <a href="..\chapter3\05_Declarations.html#function_result"><em>函数结果</em></a> <em>可选</em><br><em>函数结果</em> → <strong>-></strong> <a href="..\chapter3\06_Attributes.html#attributes"><em>特性(Attributes)列表</em></a> <em>可选</em> <a href="..\chapter3\03_Types.html#type"><em>类型</em></a><br><em>函数体</em> → <a href="..\chapter3\05_Declarations.html#code_block"><em>代码块</em></a><br><em>parameter-clauses</em> → <a href="..\chapter3\05_Declarations.html#parameter_clause"><em>参数子句</em></a> <a href="..\chapter3\05_Declarations.html#parameter_clauses"><em>parameter-clauses</em></a> <em>可选</em><br><em>参数子句</em> → <strong>(</strong> <strong>)</strong> | <strong>(</strong> <a href="..\chapter3\05_Declarations.html#parameter_list"><em>参数列表</em></a> <strong>...</strong> <em>可选</em> <strong>)</strong><br><em>参数列表</em> → <a href="..\chapter3\05_Declarations.html#parameter"><em>参数</em></a> | <a href="..\chapter3\05_Declarations.html#parameter"><em>参数</em></a> <strong>,</strong> <a href="..\chapter3\05_Declarations.html#parameter_list"><em>参数列表</em></a><br><em>参数</em> → <strong>inout</strong> <em>可选</em> <strong>let</strong> <em>可选</em> <strong>#</strong> <em>可选</em> <a href="..\chapter3\05_Declarations.html#parameter_name"><em>参数名</em></a> <a href="..\chapter3\05_Declarations.html#local_parameter_name"><em>本地参数名</em></a> <em>可选</em> <a href="..\chapter3\03_Types.html#type_annotation"><em>类型注解</em></a> <a href="..\chapter3\05_Declarations.html#default_argument_clause"><em>默认参数子句</em></a> <em>可选</em><br><em>参数</em> → <strong>inout</strong> <em>可选</em> <strong>var</strong> <strong>#</strong> <em>可选</em> <a href="..\chapter3\05_Declarations.html#parameter_name"><em>参数名</em></a> <a href="..\chapter3\05_Declarations.html#local_parameter_name"><em>本地参数名</em></a> <em>可选</em> <a href="..\chapter3\03_Types.html#type_annotation"><em>类型注解</em></a> <a href="..\chapter3\05_Declarations.html#default_argument_clause"><em>默认参数子句</em></a> <em>可选</em><br><em>参数</em> → <a href="..\chapter3\06_Attributes.html#attributes"><em>特性(Attributes)列表</em></a> <em>可选</em> <a href="..\chapter3\03_Types.html#type"><em>类型</em></a><br><em>参数名</em> → <a href="LexicalStructure.html#identifier"><em>标识符</em></a> | <strong>_</strong><br><em>本地参数名</em> → <a href="LexicalStructure.html#identifier"><em>标识符</em></a> | <strong>_</strong><br><em>默认参数子句</em> → <strong>=</strong> <a href="..\chapter3\04_Expressions.html#expression"><em>表达式</em></a> </p>
|
||||
</blockquote>
|
||||
@ -847,29 +852,28 @@ addTwoNumbers(4)(5) // Returns 9
|
||||
<p>你可以扩展枚举类型,正如在扩展名声明(Extension Declaration)中讨论的一样。</p>
|
||||
<h3 id="-">任意事件类型的枚举</h3>
|
||||
<p>如下的形式声明了一个包含任意类型枚举时间的枚举变量</p>
|
||||
<pre><code>enum enumeration name {
|
||||
case enumeration case 1
|
||||
case enumeration case 2(associated value types)
|
||||
}
|
||||
</code></pre><p>这种形式的枚举声明在其他语言中有时被叫做可识别联合(discrinminated)。</p>
|
||||
<blockquote>
|
||||
<p>enum <code>enumeration name</code> {<br> case <code>enumeration case 1</code><br> case <code>enumeration case 2</code>(<code>associated value types</code>)<br>} </p>
|
||||
</blockquote>
|
||||
<p>这种形式的枚举声明在其他语言中有时被叫做可识别联合(discrinminated)。</p>
|
||||
<p>这种形式中,每一个事件块由关键字case开始,后面紧接着一个或多个以逗号分隔的枚举事件。每一个事件名必须是
|
||||
独一无二的。每一个事件也可以指定它所存储的指定类型的值,这些类型在关联值类型的元祖里被指定,立即书写在事件
|
||||
名后。获得更多关于关联值类型的信息和例子,请查看关联值(associated values)一节。</p>
|
||||
<h3 id="-">使用原始事件值的枚举</h3>
|
||||
<p>以下的形式声明了一个包含相同基础类型的枚举事件的枚举:</p>
|
||||
<pre><code>enum enumeration name: raw value type {
|
||||
case enumeration case 1 = raw value 1
|
||||
case enumeration case 2 = raw value 2
|
||||
}
|
||||
</code></pre><p>在这种形式中,每一个事件块由case关键字开始,后面紧接着一个或多个以逗号分隔的枚举事件。和第一种形式的枚举
|
||||
<blockquote>
|
||||
<p>enum <code>enumeration name</code>: <code>raw value type</code> {<br> case <code>enumeration case 1</code> = <code>raw value 1</code><br> case <code>enumeration case 2</code> = <code>raw value 2</code><br>} </p>
|
||||
</blockquote>
|
||||
<p>在这种形式中,每一个事件块由case关键字开始,后面紧接着一个或多个以逗号分隔的枚举事件。和第一种形式的枚举
|
||||
事件不同,这种形式的枚举事件包含一个同类型的基础值,叫做原始值(raw value)。这些值的类型在原始值类型(raw value type)
|
||||
中被指定,必须是字面上的整数,浮点数,字符或者字符串。</p>
|
||||
<p>每一个事件必须有唯一的名字,必须有一个唯一的初始值。如果初始值类型被指定为int,则不必为事件显式的指定值,
|
||||
它们会隐式的被标为值0,1,2等。每一个没有被赋值的Int类型时间会隐式的赋予一个初始值,它们是自动递增的。</p>
|
||||
<pre><code>num ExampleEnum: Int {
|
||||
<pre><code class="lang-swift">num ExampleEnum: Int {
|
||||
case A, B, C = 5, D
|
||||
}
|
||||
</code></pre><p>在上面的例子中,ExampleEnum.A的值是0,ExampleEnum.B的值是。因为ExampleEnum.C的值被显式的设定为5,因此
|
||||
</code></pre>
|
||||
<p>在上面的例子中,ExampleEnum.A的值是0,ExampleEnum.B的值是。因为ExampleEnum.C的值被显式的设定为5,因此
|
||||
ExampleEnum.D的值会自动增长为6.</p>
|
||||
<p>枚举事件的初始值可以调用方法roRaw获得,如ExampleEnum.B.toRaw()。你也可以通过调用fromRaw方法来使用初始值找到
|
||||
其对应的事件,并返回一个可选的事件。查看更多信息和获取初始值类型事件的信息,参阅初始值(raw values)。</p>
|
||||
@ -884,10 +888,10 @@ ExampleEnum.D的值会自动增长为6.</p>
|
||||
<p><a name="structure_declaration"></a></p>
|
||||
<h2 id="-">结构体声明</h2>
|
||||
<p>使用结构体声明可以在你的程序里引入一个结构体类型。结构体声明使用struct关键字,遵循如下的形式:</p>
|
||||
<pre><code>struct structure name: adopted protocols {
|
||||
declarations
|
||||
}
|
||||
</code></pre><p>结构体内包含零或多个声明。这些声明可以包括存储型和计算型属性,静态属性,实例方法,静态方法,构造器,
|
||||
<blockquote>
|
||||
<p>struct <code>structure name</code>: <code>adopted protocols</code> {<br> <code>declarations</code><br>} </p>
|
||||
</blockquote>
|
||||
<p>结构体内包含零或多个声明。这些声明可以包括存储型和计算型属性,静态属性,实例方法,静态方法,构造器,
|
||||
类型别名,甚至其他结构体,类,和枚举声明。结构体声明不能包含析构器或者协议声明。详细讨论和包含多种结构体
|
||||
声明的实例,参见类和结构体一节。</p>
|
||||
<p>结构体可以包含任意数量的协议,但是不能继承自类,枚举或者其他结构体。</p>
|
||||
@ -906,10 +910,10 @@ ExampleEnum.D的值会自动增长为6.</p>
|
||||
<p><a name="class_declaration"></a></p>
|
||||
<h2 id="-">类声明</h2>
|
||||
<p>你可以在你的程序中使用类声明来引入一个类。类声明使用关键字class,遵循如下的形式:</p>
|
||||
<pre><code>class class name: superclass, adopted protocols {
|
||||
declarations
|
||||
}
|
||||
</code></pre><p>一个类内包含零或多个声明。这些声明可以包括存储型和计算型属性,实例方法,类方法,构造器,单独的析构器方法,
|
||||
<blockquote>
|
||||
<p>class <code>class name</code>: <code>superclass</code>, <code>adopted protocols</code> {<br> <code>declarations</code><br>} </p>
|
||||
</blockquote>
|
||||
<p>一个类内包含零或多个声明。这些声明可以包括存储型和计算型属性,实例方法,类方法,构造器,单独的析构器方法,
|
||||
类型别名,甚至其他结构体,类,和枚举声明。类声明不能包含协议声明。详细讨论和包含多种类声明的实例,参见类和
|
||||
结构体一节。</p>
|
||||
<p>一个类只能继承一个父类,超类,但是可以包含任意数量的协议。这些超类第一次在type-inheritance-clause出现,遵循任意协议。</p>
|
||||
@ -920,8 +924,10 @@ ExampleEnum.D的值会自动增长为6.</p>
|
||||
<p>虽然超类的属性和方法声明可以被当前类继承,但是超类声明的指定构造器却不能。这意味着,如果当前类重写了超类
|
||||
的所有指定构造器,它就继承了超类的方便构造器。Swift的类并不是继承自一个全局基础类。</p>
|
||||
<p>有两种方法来创建已声明的类的实例:</p>
|
||||
<p>-调用类的一个构造器,参见构造器(initializers)。</p>
|
||||
<p>-如果没有声明构造器,而且类的所有属性都被赋予了初始值,调用类的默认构造器,参见默认构造器(default initializers).</p>
|
||||
<ul>
|
||||
<li>调用类的一个构造器,参见构造器(initializers)。</li>
|
||||
<li>如果没有声明构造器,而且类的所有属性都被赋予了初始值,调用类的默认构造器,参见默认构造器(default initializers).</li>
|
||||
</ul>
|
||||
<p>类实例属性可以用点(.)来获得,详情参见获得属性(Accessing Properties)一节。</p>
|
||||
<p>类是引用类型;当被赋予常量或变量,函数调用时,类的实例是被引用,而不是复制。获得更多关于引用类型的信息,
|
||||
结构体和枚举都是值类型(Structures and Enumerations Are Value Types)一节。</p>
|
||||
@ -932,22 +938,19 @@ ExampleEnum.D的值会自动增长为6.</p>
|
||||
<p><a name="protocol_declaration"></a></p>
|
||||
<h2 id="-translated-by-">协议声明(translated by 小一)</h2>
|
||||
<p>一个协议声明为你的程序引入一个命名了的协议类型。协议声明使用 <code>protocol</code> 关键词来进行声明并有下面这样的形式:</p>
|
||||
<pre><code class="lang-javascript">protocol protocol name: inherited protocols {
|
||||
protocol member declarations
|
||||
}
|
||||
</code></pre>
|
||||
<blockquote>
|
||||
<p>protocol <code>protocol name</code>: <code>inherited protocols</code> {<br> <code>protocol member declarations</code><br>} </p>
|
||||
</blockquote>
|
||||
<p>协议的主体包含零或多个协议成员声明,这些成员描述了任何采用该协议必须满足的一致性要求。特别的,一个协议可以声明必须实现某些属性、方法、初始化程序及下标脚本的一致性类型。协议也可以声明专用种类的类型别名,叫做关联类型,它可以指定协议的不同声明之间的关系。协议成员声明会在下面的详情里进行讨论。</p>
|
||||
<p>协议类型可以从很多其它协议那继承。当一个协议类型从其它协议那继承的时候,来自其它协议的所有要求就集合了,而且从当前协议继承的任何类型必须符合所有的这些要求。对于如何使用协议继承的例子,查看<a href="../chapter2/21_Protocols.html#protocol_inheritance">协议继承</a></p>
|
||||
<blockquote>
|
||||
<p>注意:</p>
|
||||
<p>你也可以使用协议合成类型集合多个协议的一致性要求,详情参见<a href="../chapter3/03_Types.html#protocol_composition_type">协议合成类型</a>和<a href="../chapter2/21_Protocols.html#protocol_composition">协议合成</a></p>
|
||||
<p>注意:<br>你也可以使用协议合成类型集合多个协议的一致性要求,详情参见<a href="../chapter3/03_Types.html#protocol_composition_type">协议合成类型</a>和<a href="../chapter2/21_Protocols.html#protocol_composition">协议合成</a></p>
|
||||
</blockquote>
|
||||
<p>你可以通过采用在类型的扩展声明中的协议来为之前声明的类型添加协议一致性。在扩展中你必须实现所有采用协议的要求。如果该类型已经实现了所有的要求,你可以让这个扩展声明的主题留空。</p>
|
||||
<p>默认地,符合某一个协议的类型必须实现所有声明在协议中的属性、方法和下标脚本。也就是说,你可以用<code>optional</code>属性标注这些协议成员声明以指定它们的一致性类型实现是可选的。<code>optional</code>属性仅仅可以用于使用<code>objc</code>属性标记过的协议。这样的结果就是仅仅类类型可以采用并符合包含可选成员要求的协议。更多关于如何使用<code>optional</code>属性的信息及如何访问可选协议成员的指导——比如当你不能肯定是否一致性的类型实现了它们——参见<a href="../chapter2/21_Protocols.html#optional_protocol_requirements">可选协议要求</a></p>
|
||||
<p>为了限制协议的采用仅仅针对类类型,需要使用<code>class_protocol</code>属性标记整个协议声明。任意继承自标记有<code>class_protocol</code>属性协议的协议都可以智能地仅能被类类型采用。</p>
|
||||
<blockquote>
|
||||
<p>注意:</p>
|
||||
<p>如果协议已经用<code>object</code>属性标记了,<code>class_protocol</code>属性就隐性地应用于该协议;没有必要再明确地使用<code>class_protocol</code>属性来标记该协议了。</p>
|
||||
<p>注意:<br>如果协议已经用<code>object</code>属性标记了,<code>class_protocol</code>属性就隐性地应用于该协议;没有必要再明确地使用<code>class_protocol</code>属性来标记该协议了。</p>
|
||||
</blockquote>
|
||||
<p>协议是命名的类型,因此它们可以以另一个命名类型出现在你代码的所有地方,就像<a href="../chapter2/21_Protocols.html#protocols_as_types">协议类型</a>里讨论的那样。然而你不能构造一个协议的实例,因为协议实际上不提供它们指定的要求的实现。</p>
|
||||
<p>你可以使用协议来声明一个类的代理的方法或者应该实现的结构,就像<a href="../chapter2/21_Protocols.html#delegation">委托(代理)模式</a>描述的那样。</p>
|
||||
@ -957,8 +960,10 @@ ExampleEnum.D的值会自动增长为6.</p>
|
||||
<p><a name="protocol_property_declaration"></a></p>
|
||||
<h3 id="-">协议属性声明</h3>
|
||||
<p>协议声明了一致性类型必须在协议声明的主体里通过引入一个协议属性声明来实现一个属性。协议属性声明有一种特殊的类型声明形式:</p>
|
||||
<pre><code>var property name: type { get set }
|
||||
</code></pre><p>同其它协议成员声明一样,这些属性声明仅仅针对符合该协议的类型声明了<code>getter</code>和<code>setter</code>要求。结果就是你不需要在协议里它被声明的地方实现<code>getter</code>和<code>setter</code>。</p>
|
||||
<blockquote>
|
||||
<p>var <code>property name</code>: <code>type</code> { get set }</p>
|
||||
</blockquote>
|
||||
<p>同其它协议成员声明一样,这些属性声明仅仅针对符合该协议的类型声明了<code>getter</code>和<code>setter</code>要求。结果就是你不需要在协议里它被声明的地方实现<code>getter</code>和<code>setter</code>。</p>
|
||||
<p><code>getter</code>和<code>setter</code>要求可以通过一致性类型以各种方式满足。如果属性声明包含<code>get</code>和<code>set</code>关键词,一致性类型就可以用可读写(实现了<code>getter</code>和<code>setter</code>)的存储型变量属性或计算型属性,但是属性不能以常量属性或只读计算型属性实现。如果属性声明仅仅包含<code>get</code>关键词的话,它可以作为任意类型的属性被实现。比如说实现了协议的属性要求的一致性类型,参见<a href="../chapter2/21_Protocols.html#property_requirements">属性要求</a></p>
|
||||
<p>更多参见<a href="../chapter3/05_Declarations.html#variable_declaration">变量声明</a></p>
|
||||
<blockquote>
|
||||
@ -985,8 +990,10 @@ ExampleEnum.D的值会自动增长为6.</p>
|
||||
<h3 id="-">协议下标脚本声明</h3>
|
||||
<p>协议声明了一致性类型必须在协议声明的主体里通过引入一个协议下标脚本声明来实现一个下标脚本。协议属性声明
|
||||
对下标脚本声明有一个特殊的形式:</p>
|
||||
<pre><code>subscript (parameters) -> return type { get set }
|
||||
</code></pre><p>下标脚本声明只为和协议一致的类型声明了必需的最小数量的的getter和setter。如果下标脚本申明包含get和set关键字,
|
||||
<blockquote>
|
||||
<p>subscript (<code>parameters</code>) -> <code>return type</code> { get set }</p>
|
||||
</blockquote>
|
||||
<p>下标脚本声明只为和协议一致的类型声明了必需的最小数量的的getter和setter。如果下标脚本申明包含get和set关键字,
|
||||
一致的类型也必须有一个getter和setter语句。如果下标脚本声明值包含get关键字,一致的类型必须至少包含一个
|
||||
getter语句,可以选择是否包含setter语句。</p>
|
||||
<p>更多参阅下标脚本声明。</p>
|
||||
@ -1006,19 +1013,19 @@ getter语句,可以选择是否包含setter语句。</p>
|
||||
<p>结构体,枚举,类可以有任意数量的构造器,但是类的构造器的规则和行为是不一样的。不像结构体和枚举那样,类
|
||||
有两种结构体,designed initializers 和convenience initializers,参见构造器一节。</p>
|
||||
<p>如下的形式声明了结构体,枚举和类的指定构造器:</p>
|
||||
<pre><code>init(parameters) {
|
||||
statements
|
||||
}
|
||||
</code></pre><p>类的指定构造器将类的所有属性直接初始化。如果类有超类,它不能调用该类的其他构造器,它只能调用超类的一个
|
||||
<blockquote>
|
||||
<p>init(<code>parameters</code>) {<br> <code>statements</code><br>} </p>
|
||||
</blockquote>
|
||||
<p>类的指定构造器将类的所有属性直接初始化。如果类有超类,它不能调用该类的其他构造器,它只能调用超类的一个
|
||||
指定构造器。如果该类从它的超类处继承了任何属性,这些属性在当前类内被赋值或修饰时,必须带哦用一个超类的
|
||||
指定构造器。</p>
|
||||
<p>指定构造器可以在类声明的上下文中声明,因此它不能用扩展声明的方法加入一个类中。</p>
|
||||
<p>结构体和枚举的构造器可以带哦用其他的已声明的构造器,来委托其中一个火全部进行初始化过程。</p>
|
||||
<p>以关键字convenience来声明一个类的便利构造器:</p>
|
||||
<pre><code>convenience init(parameters) {
|
||||
statements
|
||||
}
|
||||
</code></pre><p>便利构造器可以将初始化过程委托给另一个便利构造器或类的一个指定构造器。这意味着,类的初始化过程必须
|
||||
<blockquote>
|
||||
<p>convenience init(<code>parameters</code>) {<br> <code>statements</code><br>} </p>
|
||||
</blockquote>
|
||||
<p>便利构造器可以将初始化过程委托给另一个便利构造器或类的一个指定构造器。这意味着,类的初始化过程必须
|
||||
以一个将所有类属性完全初始化的指定构造器的调用作为结束。便利构造器不能调用超类的构造器。</p>
|
||||
<p>你可以使用requierd关键字,将便利构造器和指定构造器标记为每个子类的构造器都必须拥有的。因为指定构造器
|
||||
不被子类继承,它们必须被立即执行。当子类直接执行所有超类的指定构造器(或使用便利构造器重写指定构造器)时,
|
||||
@ -1031,10 +1038,10 @@ overrride关键字。</p>
|
||||
<p><a name="deinitializer_declaration"></a></p>
|
||||
<h2 id="-">析构声明</h2>
|
||||
<p>析构声明为类声明了一个析构器。析构器没有参数,遵循如下的格式:</p>
|
||||
<pre><code>deinit {
|
||||
statements
|
||||
}
|
||||
</code></pre><p>当类没有任何语句时将要被释放时,析构器会自动的被调用。析构器在类的声明体内只能被声明一次——但是不能在
|
||||
<blockquote>
|
||||
<p>deinit {<br> <code>statements</code><br>} </p>
|
||||
</blockquote>
|
||||
<p>当类没有任何语句时将要被释放时,析构器会自动的被调用。析构器在类的声明体内只能被声明一次——但是不能在
|
||||
类的扩展声明内,每个类最多只能有一个。</p>
|
||||
<p>子类继承了它的超类的析构器,在子类将要被释放时隐式的调用。子类在所有析构器被执行完毕前不会被释放。</p>
|
||||
<p>析构器不会被直接调用。</p>
|
||||
@ -1045,10 +1052,10 @@ overrride关键字。</p>
|
||||
<p><a name="extension_declaration"></a></p>
|
||||
<h2 id="-">扩展声明</h2>
|
||||
<p>扩展声明用于扩展一个现存的类,结构体,枚举的行为。扩展声明以关键字extension开始,遵循如下的规则:</p>
|
||||
<pre><code>extension type: adopted protocols {
|
||||
declarations
|
||||
}
|
||||
</code></pre><p>一个扩展声明体包括零个或多个声明。这些声明可以包括计算型属性,计算型静态属性,实例方法,静态和类方法,构造器,
|
||||
<blockquote>
|
||||
<p>extension <code>type</code>: <code>adopted protocols</code> {<br> <code>declarations</code><br>} </p>
|
||||
</blockquote>
|
||||
<p>一个扩展声明体包括零个或多个声明。这些声明可以包括计算型属性,计算型静态属性,实例方法,静态和类方法,构造器,
|
||||
下标脚本声明,甚至其他结构体,类,和枚举声明。扩展声明不能包含析构器,协议声明,存储型属性,属性监测器或其他
|
||||
的扩展属性。详细讨论和查看包含多种扩展声明的实例,参见扩展一节。</p>
|
||||
<p>扩展声明可以向现存的类,结构体,枚举内添加一致的协议。扩展声明不能向一个类中添加继承的类,因此
|
||||
@ -1061,37 +1068,11 @@ type-inheritance-clause是一个只包含协议列表的扩展声明。</p>
|
||||
</blockquote>
|
||||
<p><a name="subscript_declaration"></a></p>
|
||||
<h2 id="-translated-by-">下标脚本声明(translated by 林)</h2>
|
||||
<p><<<<<<< HEAD
|
||||
附属脚本用于向特定类型添加附属脚本支持,通常为访问集合,列表和序列的元素时提供语法便利。附属脚本声明使用关键字<code>subscript</code>,声明形式如下:</p>
|
||||
<p>附属脚本用于向特定类型添加附属脚本支持,通常为访问集合,列表和序列的元素时提供语法便利。附属脚本声明使用关键字<code>subscript</code>,声明形式如下:</p>
|
||||
<blockquote>
|
||||
<p>subscript (<code>parameter</code>) -> (return type){<br> get{<br> <code>statements</code><br> }<br> set(<code>setter name</code>){<br> <code>statements</code><br> }<br>} </p>
|
||||
</blockquote>
|
||||
<h1 id="-">附属脚本声明只能在类,结构体,枚举,扩展和协议声明的上下文进行声明。</h1>
|
||||
<p>下标脚本用于向特定类型添加下标脚本支持,通常为访问集合,列表和序列的元素时提供语法便利。下标脚本声明使用关键字<code>subscript</code>,声明形式如下:</p>
|
||||
<blockquote>
|
||||
<p>subscript (<code>parameter</code>) -> (return type){
|
||||
get{
|
||||
<code>statements</code>
|
||||
}
|
||||
set(<code>setter name</code>){
|
||||
<code>statements</code>
|
||||
}
|
||||
}
|
||||
下标脚本声明只能在类,结构体,枚举,扩展和协议声明的上下文进行声明。</p>
|
||||
<blockquote>
|
||||
<blockquote>
|
||||
<blockquote>
|
||||
<blockquote>
|
||||
<blockquote>
|
||||
<blockquote>
|
||||
<p>a516af6a531a104ec88da0d236ecf389a5ec72af</p>
|
||||
</blockquote>
|
||||
</blockquote>
|
||||
</blockquote>
|
||||
</blockquote>
|
||||
</blockquote>
|
||||
</blockquote>
|
||||
</blockquote>
|
||||
<p>附属脚本声明只能在类,结构体,枚举,扩展和协议声明的上下文进行声明。</p>
|
||||
<p><em>变量(parameters)</em>指定一个或多个用于在相关类型的下标脚本中访问元素的索引(例如,表达式<code>object[i]</code>中的<code>i</code>)。尽管用于元素访问的索引可以是任意类型的,但是每个变量必须包含一个用于指定每种索引类型的类型标注。<em>返回类型(return type)</em>指定被访问的元素的类型。</p>
|
||||
<p>和计算性属性一样,下标脚本声明支持对访问元素的读写操作。getter用于读取值,setter用于写入值。setter子句是可选的,当仅需要一个getter子句时,可以将二者都忽略且直接返回请求的值即可。也就是说,如果使用了setter子句,就必须使用getter子句。</p>
|
||||
<p>setter的名字和封闭的括号是可选的。如果使用了setter名称,它会被当做传给setter的变量的名称。如果不使用setter名称,那么传给setter的变量的名称默认是<code>value</code>。setter名称的类型必须与<em>返回类型(return type)</em>的类型相同。</p>
|
||||
@ -1108,10 +1089,7 @@ type-inheritance-clause是一个只包含协议列表的扩展声明。</p>
|
||||
运算符声明有三种基本形式,每种缀性各一种。运算符的缀性通过在<code>operator</code>和运算符之间添加上下文关键字<code>infix</code>,<code>prefix</code>或<code>postfix</code>来指定。每种形式中,运算符的名字只能包含<a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/doc/uid/TP40014097-CH30-XID_871" target="_blank">Operators</a>中定义的运算符字符。</p>
|
||||
<p>下面的这种形式声明了一个新的中缀运算符:</p>
|
||||
<blockquote>
|
||||
<p>operator infix <code>operator name</code>{
|
||||
precedence <code>precedence level</code>
|
||||
associativity <code>associativity</code>
|
||||
}</p>
|
||||
<p>operator infix <code>operator name</code>{<br> previewprecedence <code>precedence level</code><br> associativity <code>associativity</code><br>} </p>
|
||||
</blockquote>
|
||||
<p><em>中缀</em>运算符是二元运算符,它可以被置于两个操作数之间,比如表达式<code>1 + 2</code> 中的加法运算符(<code>+</code>)。</p>
|
||||
<p>中缀运算符可以可选地指定优先级,结合性,或两者同时指定。</p>
|
||||
@ -1121,13 +1099,13 @@ type-inheritance-clause是一个只包含协议列表的扩展声明。</p>
|
||||
<p>声明时不指定任何优先级或结合性的中缀运算符,它们的优先级会被初始化为100,结合性被初始化为<code>none</code>。</p>
|
||||
<p>下面的这种形式声明了一个新的前缀运算符:</p>
|
||||
<blockquote>
|
||||
<p>operator prefix <code>operator name</code>{}</p>
|
||||
<p>operator prefix <code>operator name</code>{} </p>
|
||||
</blockquote>
|
||||
<p>紧跟在操作数前边的<em>前缀运算符(prefix operator)</em>是一元运算符,例如表达式<code>++i</code>中的前缀递增运算符(<code>++</code>)。</p>
|
||||
<p>前缀运算符的声明中不指定优先级。前缀运算符是非结合的。</p>
|
||||
<p>下面的这种形式声明了一个新的后缀运算符:</p>
|
||||
<blockquote>
|
||||
<p>operator postfix <code>operator name</code>{}</p>
|
||||
<p>operator postfix <code>operator name</code>{} </p>
|
||||
</blockquote>
|
||||
<p>紧跟在操作数后边的<em>后缀运算符(postfix operator)</em>是一元运算符,例如表达式<code>i++</code>中的前缀递增运算符(<code>++</code>)。</p>
|
||||
<p>和前缀运算符一样,后缀运算符的声明中不指定优先级。后缀运算符是非结合的。</p>
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="3.7" data-basepath=".." data-revision="1402750255397">
|
||||
<div class="book" data-level="3.7" data-basepath=".." data-revision="1402759431779">
|
||||
<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_81">
|
||||
<section class="normal" id="section-gitbook_557">
|
||||
|
||||
<blockquote>
|
||||
<p>翻译:Hawstein</p>
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="3.8" data-basepath=".." data-revision="1402750255397">
|
||||
<div class="book" data-level="3.8" data-basepath=".." data-revision="1402759431779">
|
||||
<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_93">
|
||||
<section class="normal" id="section-gitbook_569">
|
||||
|
||||
<blockquote>
|
||||
<p>翻译:honghaoz</p>
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="3.9" data-basepath=".." data-revision="1402750255397">
|
||||
<div class="book" data-level="3.9" data-basepath=".." data-revision="1402759431779">
|
||||
<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_95">
|
||||
<section class="normal" id="section-gitbook_571">
|
||||
|
||||
<blockquote>
|
||||
<p>翻译:fd5788</p>
|
||||
|
||||
File diff suppressed because one or more lines are too long
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="3.5" data-basepath=".." data-revision="1402750255397">
|
||||
<div class="book" data-level="3.5" data-basepath=".." data-revision="1402759431779">
|
||||
<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_97">
|
||||
<section class="normal" id="section-gitbook_576">
|
||||
|
||||
<blockquote>
|
||||
<p>翻译:coverxit</p>
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="3" data-basepath=".." data-revision="1402750255397">
|
||||
<div class="book" data-level="3" data-basepath=".." data-revision="1402759431779">
|
||||
<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>
|
||||
|
||||
@ -44,7 +44,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="0" data-basepath="." data-revision="1402750255397">
|
||||
<div class="book" data-level="0" data-basepath="." data-revision="1402759431779">
|
||||
<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_29">
|
||||
<section class="normal" id="section-gitbook_505">
|
||||
|
||||
<blockquote>
|
||||
<p>Swift 中文翻译组:364279588(要求对翻译感兴趣)</p>
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
CACHE MANIFEST
|
||||
# Revision 1402750255398
|
||||
# Revision 1402759431780
|
||||
|
||||
CACHE:
|
||||
index.html
|
||||
@ -14,11 +14,11 @@ chapter2/05_Control_Flow.html
|
||||
chapter2/06_Functions.html
|
||||
chapter2/07_Closures.html
|
||||
chapter2/08_Enumerations.html
|
||||
chapter2/09_Classes_and_Structures.html
|
||||
chapter2/10_Properties.html
|
||||
chapter2/11_Methods.html
|
||||
chapter2/12_Subscripts.html
|
||||
chapter2/02_Basic_Operators.html
|
||||
chapter2/10_Properties.html
|
||||
chapter2/09_Classes_and_Structures.html
|
||||
chapter2/14_Initialization.html
|
||||
chapter2/15_Deinitialization.html
|
||||
chapter2/16_Automatic_Reference_Counting.html
|
||||
@ -28,19 +28,19 @@ chapter2/19_Nested_Types.html
|
||||
chapter2/20_Extensions.html
|
||||
chapter2/21_Protocols.html
|
||||
chapter2/22_Generics.html
|
||||
chapter2/23_Advanced_Operators.html
|
||||
chapter2/chapter2.html
|
||||
chapter2/23_Advanced_Operators.html
|
||||
chapter3/06_Attributes.html
|
||||
chapter3/01_About_the_Language_Reference.html
|
||||
chapter3/03_Types.html
|
||||
chapter3/04_Expressions.html
|
||||
chapter3/02_Lexical_Structure.html
|
||||
chapter3/05_Declarations.html
|
||||
chapter3/02_Lexical_Structure.html
|
||||
chapter3/07_Patterns.html
|
||||
chapter3/08_Generic_Parameters_and_Arguments.html
|
||||
chapter3/10_Statements.html
|
||||
chapter3/09_Summary_of_the_Grammar.html
|
||||
chapter3/chapter3.html
|
||||
chapter3/10_Statements.html
|
||||
gitbook/app.js
|
||||
gitbook/fonts/anonymouspro/400.woff
|
||||
gitbook/fonts/anonymouspro/400i.woff
|
||||
|
||||
File diff suppressed because one or more lines are too long
@ -13,7 +13,7 @@
|
||||
- [协议类型(Protocols as Types)](#protocols_as_types)
|
||||
- [委托(代理)模式(Delegation)](#delegation)
|
||||
- [在扩展中添加协议成员(Adding Protocol Conformance with an Extension)](#adding_protocol_conformance_with_an_extension)
|
||||
- [通过延展补充协议声明(Declaring Protocol Adoption with an Extension)](#declaring_protocol_adoption_with_an_extension)
|
||||
- [通过扩展补充协议声明(Declaring Protocol Adoption with an Extension)](#declaring_protocol_adoption_with_an_extension)
|
||||
- [集合中的协议类型(Collections of Protocol Types)](#collections_of_protocol_types)
|
||||
- [协议的继承(Protocol Inheritance)](#protocol_inheritance)
|
||||
- [协议合成(Protocol Composition)](#protocol_composition)
|
||||
@ -54,7 +54,9 @@ class SomeClass: SomeSuperClass, FirstProtocol, AnotherProtocol {
|
||||
<a name="property_requirements"></a>
|
||||
## 属性要求
|
||||
|
||||
`协议`能够要求其`遵循者`必须含有一些**特定名称和类型**的`实例属性(instance property)`或`类属性 (type property)`,也能够要求属性的`(设置权限)settable` 和`(访问权限)gettable`,但它不要求`属性`是`存储型属性(stored property)`还是`计算型属性(calculate property)`。
|
||||
`协议`能够要求其`遵循者`必须含有一些**特定名称和类型**的`实例属性(instance property)`或`类属性 (type property)`,也能够要求属性具有`(设置权限)settable` 和`(访问权限)gettable`,但它不要求`属性`是`存储型属性(stored property)`还是`计算型属性(calculate property)`。
|
||||
|
||||
如果协议要求属性具有设置权限和访问权限,那常量存储型属性或者只读计算型属性都无法满足此要求。如果协议只要求属性具有访问权限,那任何类型的属性都可以满足此要求,无论这些属性是否具有设置权限。
|
||||
|
||||
通常前置`var`关键字将属性声明为变量。在属性声明后写上`{ get set }`表示属性为可读写的。`{ get }`用来表示属性为可读的。即使你为可读的属性实现了`setter`方法,它也不会出错。
|
||||
|
||||
@ -400,7 +402,7 @@ println(game.asText())
|
||||
```
|
||||
|
||||
<a name="declaring_protocol_adoption_with_an_extension"></a>
|
||||
## 通过延展补充协议声明
|
||||
## 通过扩展补充协议声明
|
||||
|
||||
当一个类型已经实现了协议中的所有要求,却没有声明时,可以通过`扩展`来补充协议声明:
|
||||
|
||||
|
||||
Reference in New Issue
Block a user