This commit is contained in:
numbbbbb
2014-06-12 07:39:58 +08:00
parent 6a36170118
commit 75426a3479
80 changed files with 9089 additions and 5505 deletions

View File

@ -5,12 +5,12 @@
<meta charset="UTF-8">
<title>类和结构体 | Swift 编程语言</title>
<title>《The Swift Programming Language》中文版</title>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
<meta name="robots" content="index, follow">
<meta name="author" content="">
<meta name="description" content="Swift 是苹果在 WWDC 2014 上发布的一款全新的编程语言,本书译自苹果官方的 Swift 教程《The Swift Programming Language》。">
<meta name="description" content="Swift 中文翻译组364279588要求对翻译感兴趣">
<meta name="keywords" content="gitbook,github" >
<meta name="generator" content="www.gitbook.io">
@ -21,8 +21,8 @@
<link rel="prev" href="../chapter2/08_Enumerations.html" />
<meta property="og:title" content="类和结构体 | Swift 编程语言">
<meta property="og:site_name" content="Swift 编程语言">
<meta property="og:title" content="类和结构体 | 这一次,让中国和世界同步">
<meta property="og:site_name" content="这一次,让中国和世界同步">
<meta property="og:type" content="book">
<meta property="og:locale" content="en_US">
@ -46,7 +46,7 @@
<div class="book" data-level="2.9" data-basepath=".." data-revision="1402493167130">
<div class="book" data-level="2.9" data-basepath=".." data-revision="1402523087598">
<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>
@ -98,7 +98,7 @@
<!-- Title -->
<h1>
<i class="fa fa-spinner fa-spin"></i>
<a href="../" >Swift 编程语言</a>
<a href="../" >这一次,让中国和世界同步</a>
</h1>
</div>
@ -119,7 +119,7 @@
<li data-level="0" data-path="index.html">
<a href="../"><i class="fa fa-check"></i> Introduction</a>
<a href="../"><i class="fa fa-check"></i> </a>
</li>
@ -331,7 +331,7 @@
<li class="chapter " data-level="2.19" data-path="chapter2/19_Nested_Types.html">
<a href="../chapter2/19_Nested_Types.html">
<i class="fa fa-check"></i> <b>2.19.</b> 嵌套类型
<i class="fa fa-check"></i> <b>2.19.</b> 类型嵌套
</a>
@ -534,7 +534,7 @@
<a href="../chapter2/18_Type_Casting.html" title="类型检查" class="chapter done " data-progress="2.18" style="left: 36.8421052631579%;"></a>
<a href="../chapter2/19_Nested_Types.html" title="嵌套类型" class="chapter done " data-progress="2.19" style="left: 39.473684210526315%;"></a>
<a href="../chapter2/19_Nested_Types.html" title="类型嵌套" class="chapter done " data-progress="2.19" style="left: 39.473684210526315%;"></a>
<a href="../chapter2/02_Basic_Operators.html" title="基本运算符" class="chapter done " data-progress="2.2" style="left: 42.10526315789474%;"></a>
@ -587,22 +587,28 @@
<div class="page-inner">
<section class="normal" id="section-gitbook_137">
<section class="normal" id="section-gitbook_6487">
<h3 id="-">类和结构体</h3>
<blockquote>
<p>翻译JaySurplus</p>
<p>校对sg552</p>
</blockquote>
<h1 id="-">类和结构体</h1>
<p>本页包含内容:</p>
<ul>
<li>类和结构体对比</li>
<li>结构体和枚举是值类型</li>
<li>类是引用类型</li>
<li>类和结构体的选择</li>
<li>集合collection类型的赋值与复制行为</li>
<li><a href="#comparing_classes_and_structures">类和结构体对比</a></li>
<li><a href="#structures_and_enumerations_are_value_types">结构体和枚举是值类型</a></li>
<li><a href="#classes_are_reference_types">类是引用类型</a></li>
<li><a href="#choosing_between_classes_and_structures">类和结构体的选择</a></li>
<li><a href="#assignment_and_copy_behavior_for_collection_types">集合collection类型的赋值与复制行为</a></li>
</ul>
<p>类和结构体是人们构建代码所用的一种通用且灵活的构造体。为了在类和结构体中实现各种功能,我们必须要严格按照对于常量,变量以及函数所规定的语法规则来定义属性和添加方法。</p>
<p>与其他编程语言所不同的是Swift 并不要求你为自定义类和结构去创建独立的接口和实现文件。你所要做的是在一个单一文件中定义一个类或者结构体,系统将会自动生成面向其它代码的外部接口。</p>
<blockquote>
<p> 注意:</p>
<p>通常一个<code></code>的实例被称为<code>对象</code>。然而在Swift 中,类和结构体的关系要比在其他语言中更加的密切,本章中所讨论的大部分功能都可以用在类和结构体上。因此,我们会主要使用<code>实例</code>而不是<code>对象</code></p>
</blockquote>
<p><a name="comparing_classes_and_structures"></a></p>
<h3 id="-">类和结构体对比</h3>
<p>Swift 中类和结构体有很多共同点。共同处在于:</p>
<ul>
@ -613,7 +619,7 @@
<li>通过扩展以增加默认实现的功能</li>
<li>符合协议以对某类提供标准功能</li>
</ul>
<p>更多信息请参见 <a href="http://" target="_blank">属性</a><a href="http://" target="_blank">方法</a><a href="http://" target="_blank">下标</a><a href="http://" target="_blank">初始</a><a href="http://" target="_blank">扩展</a>,和<a href="http://" target="_blank">协议</a></p>
<p>更多信息请参见 <a href="10_Properties.html">属性</a><a href="11_Methods.html">方法</a><a href="12_Subscripts.html">下标</a><a href="14_Initialization.html">初始过程</a><a href="20_Extensions.html">扩展</a>,和<a href="21_Protocols.html">协议</a></p>
<p>与结构体相比,类还有如下的附加功能:</p>
<ul>
<li>继承允许一个类继承另一个类的特征</li>
@ -623,6 +629,7 @@
</ul>
<p>更多信息请参见<a href="http://" target="_blank">继承</a><a href="http://" target="_blank">类型转换</a><a href="http://" target="_blank">初始化</a>,和<a href="http://" target="_blank">自动引用计数</a></p>
<blockquote>
<p>注意:</p>
<p>结构体总是通过被复制的方式在代码中传递,因此请不要使用引用计数。</p>
</blockquote>
<h3 id="-">定义</h3>
@ -634,7 +641,8 @@ struct SomeStructure {
// structure definition goes here
}
</code></pre><blockquote>
<p>在你每次定义一个新类或者结构体的时候实际上你是有效地定义了一个新的Swift 类型。因此请使用 <code>UpperCamelCase</code> 这种方式来命名(如 <code>SomeClass</code><code>SomeStructure</code>以便符合标准Swift 类型的大写命名风格(如<code>String</code><code>Int</code><code>Bool</code>)。相反的,请使用<code>lowerCamelCase</code>这种方式为属性和方法命名(如<code>framerate</code><code>incrementCount</code>),以便和类区分。</p>
<p> 注意:</p>
<p>在你每次定义一个新类或者结构体的时候,实际上你是有效地定义了一个新的 Swift 类型。因此请使用 <code>UpperCamelCase</code> 这种方式来命名(如 <code>SomeClass</code><code>SomeStructure</code>以便符合标准Swift 类型的大写命名风格(如<code>String</code><code>Int</code><code>Bool</code>)。相反的,请使用<code>lowerCamelCase</code>这种方式为属性和方法命名(如<code>framerate</code><code>incrementCount</code>),以便和类区分。</p>
</blockquote>
<p>以下是定义结构体和定义类的示例:</p>
<pre><code>struct Resolution {
@ -654,44 +662,46 @@ class VideoMode {
<p>生成结构体和类实例的语法非常相似:</p>
<pre><code>let someResolution = Resolution()
let someVideoMode = VideoMode()
</code></pre><p>结构体和类都使用初始化器语法来生成新的实例。初始化器语法的最简单形式是在结构体或者类的类型名称后跟随一个空括弧,如<code>Resolution()</code><code>VideoMode()</code>。通过这种方式所创建的类或者结构体实例,其属均会被初始化为默认值。<a href="http://" target="_blank">Initialization</a>章节会对类和结构体的初始化进行更详细的讨论。</p>
</code></pre><p>结构体和类都使用初始化器语法来生成新的实例。初始化器语法的最简单形式是在结构体或者类的类型名称后跟随一个空括弧,如<code>Resolution()</code><code>VideoMode()</code>。通过这种方式所创建的类或者结构体实例,其属均会被初始化为默认值。<a href="14_Initialization.html">构造过程</a>章节会对类和结构体的初始化进行更详细的讨论。</p>
<h3 id="-">属性访问</h3>
<p>通过使用<em>点语法</em><em>dot syntax</em>,你可以访问实例中所含有的属性。其语法规则是,实例名后面紧跟属性名,两者通过点号(.)连接:</p>
<pre><code>println(&quot;The width of someResolution is \(someResolution.width)&quot;)
// prints &quot;The width of someResolution is 0&quot;
// 输出 &quot;The width of someResolution is 0&quot;
</code></pre><p>在上面的例子中,<code>someResolution.width</code>引用<code>someResolution</code><code>width</code>属性,返回<code>width</code>的初始值<code>0</code></p>
<p>你也可以访问子属性,如何<code>VideoMode</code><code>Resolution</code>属性的<code>width</code>属性:</p>
<pre><code>println(&quot;The width of someVideoMode is \(someVideoMode.resolution.width)&quot;)
// prints &quot;The width of someVideoMode is 0&quot;
// 输出 &quot;The width of someVideoMode is 0&quot;
</code></pre><p>你也可以使用点语法为属性变量赋值:</p>
<pre><code>someVideoMode.resolution.width = 12880
println(&quot;The width of someVideoMode is now \(someVideoMode.resolution.width)&quot;)
// prints &quot;The width of someVideoMode is now 1280&quot;
// 输出 &quot;The width of someVideoMode is now 1280&quot;
</code></pre><blockquote>
<p>与Objective-C 语言不同的是Swift 允许直接设置结构体属性的子属性。上面的最后一个例子,就是直接设置了<code>someVideoMode</code><code>resolution</code>属性的<code>width</code>这个子属性,以上操作并不需要从新设置<code>resolution</code>属性。</p>
<p> 注意:</p>
<p>与 Objective-C 语言不同的是Swift 允许直接设置结构体属性的子属性。上面的最后一个例子,就是直接设置了<code>someVideoMode</code><code>resolution</code>属性的<code>width</code>这个子属性,以上操作并不需要从新设置<code>resolution</code>属性。</p>
</blockquote>
<h3 id="-">结构体类型的成员逐一初始化器</h3>
<p>//Memberwise Initializers for structure Types</p>
<p>所有结构体都有一个自动生成的成员逐一初始化器,用于初始化新结构体实例中成员的属性。新实例中各个属性的初始值可以通过属性的名称传递到成员逐一初始化器之中:</p>
<pre><code>let vga = resolutionwidth:640, heigth: 480
</code></pre><p>与结构体不同,类实例没有默认的成员逐一初始化器。<a href="http://" target="_blank">Initialization</a>章节会对初始化器进行更详细的讨论。</p>
<h3 id="-">结构体和枚举是值类型</h3>
</code></pre><p>与结构体不同,类实例没有默认的成员逐一初始化器。<a href="14_Initialization.html">构造过程</a>章节会对初始化器进行更详细的讨论。</p>
<p><a name="structures_and_enumerations_are_value_types"></a></p>
<h2 id="-">结构体和枚举是值类型</h2>
<p>值类型被赋予给一个变量,常数或者本身被传递给一个函数的时候,实际上操作的是其的拷贝。</p>
<p>在之前的章节中我们已经大量使用了值类型。实际上在Swift 中,所有的基本类型:整数(Integer)、浮点数(floating-point)、布尔值(Booleans)、字符串(string)、数组(array)和字典(dictionaries),都是值类型,并且都是以结构体的形式在后台所实现。</p>
<p>在Swift中所有的结构体和枚举都是值类型。这意味着它们的实例以及实例中所包含的任何值类型属性在代码中传递的时候都会被复制。</p>
<p>在之前的章节中,我们已经大量使用了值类型。实际上,在 Swift 中,所有的基本类型:整数(Integer)、浮点数(floating-point)、布尔值(Booleans)、字符串(string)、数组(array)和字典(dictionaries),都是值类型,并且都是以结构体的形式在后台所实现。</p>
<p> Swift 中,所有的结构体和枚举都是值类型。这意味着它们的实例,以及实例中所包含的任何值类型属性,在代码中传递的时候都会被复制。</p>
<p>请看下面这个示例,其使用了前一个示例中<code>Resolution</code>结构体:</p>
<pre><code>let hd = Resolution(width: 1920, height: 1080)
var cinema = hd
</code></pre><p>在以上示例中,声明了一个名为<code>hd</code>的常量,其值为一个初始化为全高清视频分辨率(1920像素宽1080像素高)的<code>Resolution</code>实例。</p>
</code></pre><p>在以上示例中,声明了一个名为<code>hd</code>的常量,其值为一个初始化为全高清视频分辨率(1920 像素宽1080 像素高)的<code>Resolution</code>实例。</p>
<p>然后示例中又声明了一个名为<code>cinema</code>的变量,其值为之前声明的<code>hd</code>。因为<code>Resolution</code>是一个结构体,所以<code>cinema</code>的值其实是<code>hd</code>的一个拷贝副本,而不是<code>hd</code>本身。尽管<code>hd</code><code>cinema</code>有着相同的宽(width)和高(height)属性,但是在后台中,它们是两个完全不同的实例。</p>
<p>下面,为了符合数码影院放映的需求(2048像素宽1080像素高)<code>cinema</code><code>width</code>属性需要作如下修改:</p>
<p>下面,为了符合数码影院放映的需求(2048 像素宽1080 像素高)<code>cinema</code><code>width</code>属性需要作如下修改:</p>
<pre><code>cinema.width = 2048
</code></pre><p>这里,将会显示<code>cinema</code><code>width</code>属性确已改为了<code>2048</code></p>
<pre><code>println(&quot;cinema is now \(cinema.width) pixels wide&quot;)
// prints &quot;cinema is now 2048 pixels wide&quot;
// 输出 &quot;cinema is now 2048 pixels wide&quot;
</code></pre><p>然而,初始的<code>hd</code>实例中<code>width</code>属性还是<code>1920</code></p>
<pre><code>println(&quot;hd is still \(hd.width ) pixels wide&quot;)
// prints &quot;hd is still 1920 pixels wide&quot;
// 输出 &quot;hd is still 1920 pixels wide&quot;
</code></pre><p>在将<code>hd</code>赋予给<code>cinema</code>的时候,实际上是将<code>hd</code>中所储存的<code>值(values)</code>进行拷贝,然后将拷贝的数据储存到新的<code>cinema</code>实例中。结果就是两个完全独立的实例碰巧包含有相同的数值。由于两者相互独立,因此将<code>cinema</code><code>width</code>修改为<code>2048</code>并不会影响<code>hd</code>中的宽(width)。</p>
<p>枚举也遵循相同的行为准则:</p>
<pre><code>enum CompassPoint {
@ -703,9 +713,10 @@ currentDirection = .East
if rememberDirection == .West {
println(&quot;The remembered direction is still .West&quot;)
}
// prints &quot;The remembered direction is still .West&quot;
// 输出 &quot;The remembered direction is still .West&quot;
</code></pre><p>上例中<code>rememberedDirection</code>被赋予了<code>currentDirection</code>的值(value),实际上它被赋予的是值(value)的一个拷贝。赋值过程结束后再修改<code>currentDirection</code>的值并不影响<code>rememberedDirection</code>所储存的原始值(value)的拷贝。</p>
<h3 id="-">类是引用类型</h3>
<p><a name="classes_are_reference_types"></a></p>
<h2 id="-">类是引用类型</h2>
<p>与值类型不同,引用类型在被赋予到一个变量,常量或者被传递到一个函数时,操作的并不是其拷贝。因此,引用的是已存在的实例本身而不是其拷贝。</p>
<p>请看下面这个示例,其使用了之前定义的<code>VideoMode</code>类:</p>
<pre><code>let tenEighty = VideoMode()
@ -720,7 +731,7 @@ alsoTenEighty.frameRate = 30.0
</code></pre><p>因为类是引用类型,所以<code>tenEight</code><code>alsoTenEight</code>实际上引用的是相同的<code>VideoMode</code>实例。换句话说,它们只是同一个实例的两种叫法。</p>
<p>下面,通过查看<code>tenEighty</code><code>frameRate</code>属性,我们会发现它正确的显示了基本<code>VideoMode</code>实例的新帧率,其值为<code>30.0</code></p>
<pre><code>println(&quot;The frameRate property of tenEighty is now \(tenEighty.frameRate)&quot;)
// prints &quot;The frameRate property of theEighty is now 30.0&quot;
// 输出 &quot;The frameRate property of theEighty is now 30.0&quot;
</code></pre><p>需要注意的是<code>tenEighty</code><code>alsoTenEighty</code>被声明为<em>常量(constants)</em>而不是变量。然而你依然可以改变<code>tenEighty.frameRate</code><code>alsoTenEighty.frameRate</code>,因为这两个常量本身不会改变。它们并不<code>储存</code>这个<code>VideoMode</code>实例,在后台仅仅是对<code>VideoMode</code>实例的引用。所以,改变的是被引用的基础<code>VideoMode</code><code>frameRate</code>参数,而不改变常量的值。</p>
<h3 id="-">恒等运算符</h3>
<p>因为类是引用类型,有可能有多个常量和变量在后台同时引用某一个类实例。(对于结构体和枚举来说,这并不成立。因为它们作值类型,在被赋予到常量,变量或者传递到函数时,总是会被拷贝。)</p>
@ -733,16 +744,17 @@ alsoTenEighty.frameRate = 30.0
<pre><code>if tenEighty === alsoTenTighty {
println(&quot;tenTighty and alsoTenEighty refer to the same Resolution instance.&quot;)
}
//prints &quot;tenEighty and alsoTenEighty refer to the same Resolution instance.&quot;
//输出 &quot;tenEighty and alsoTenEighty refer to the same Resolution instance.&quot;
</code></pre><p>请注意“等价于”(用三个等号表示,===) 与“等于”(用两个等号表示,==)的不同:</p>
<ul>
<li>“等价于”表示两个类类型(class type)的常量或者变量引用同一个类实例。</li>
<li>“等于”表示两个实例的值“相等”或“相同”,判定时要遵照类设计者定义定义的评判标准,因此相比于“相等”,这是一种更加合适的叫法。</li>
</ul>
<p>当你在定义你的自定义类和结构体的时候,你有义务来决定判定两个实例“相等”的标准。在章节<a href="http://" target="_blank">Equivalence Operators</a>中将会详细介绍实现自定义“等于”和“不等于”运算符的流程。</p>
<p>当你在定义你的自定义类和结构体的时候,你有义务来决定判定两个实例“相等”的标准。在章节<a href="23_Advanced_Operators.html#operator_functions">运算符函数(Operator Functions)</a>中将会详细介绍实现自定义“等于”和“不等于”运算符的流程。</p>
<h3 id="-">指针</h3>
<p>如果你有CC++或者Objective-C语言的经验那么你也许会知道这些语言使用指针来引用内存中的地址。一个Swift 常量或者变量引用一个引用类型的实例与C语言中的指针类似不同的是并不直接指向内存中的某个地址而且也不要求你使用星号(*)来表明你在创建一个引用。Swift 中这些引用与其它的常量或变量的定义方式相同。</p>
<h3 id="-">类和结构体的选择</h3>
<p>如果你有 CC++ 或者 Objective-C 语言的经验,那么你也许会知道这些语言使用指针来引用内存中的地址。一个 Swift 常量或者变量引用一个引用类型的实例与C语言中的指针类似不同的是并不直接指向内存中的某个地址而且也不要求你使用星号(*)来表明你在创建一个引用。Swift 中这些引用与其它的常量或变量的定义方式相同。</p>
<p><a name="choosing_between_classes_and_structures"></a></p>
<h2 id="-">类和结构体的选择</h2>
<p>在你的代码中,你可以使用类和结构体来定义你的自定义数据类型。</p>
<p>然而,结构体实例总是通过值传递,类实例总是通过引用传递。这意味两者适用不同的任务。当你的在考虑一个工程项目的数据构造和功能的时候,你需要决定每个数据构造是定义成类还是结构体。</p>
<p>按照通用的准则,当符合一条或多条以下条件时,请考虑构建结构体:</p>
@ -759,15 +771,17 @@ alsoTenEighty.frameRate = 30.0
<li>三维坐标系内一点,封装<code>x</code><code>y</code><code>z</code>属性,三者均为<code>Double</code>类型。</li>
</ul>
<p>在所有其它案例中,定义一个类,生成一个它的实例,并通过引用来管理和传递。实际中,这意味着绝大部分的自定义数据构造都应该是类,而非结构体。</p>
<h3 id="-collection-">集合(Collection)类型的赋值和拷贝行为</h3>
<p><a name="assignment_and_copy_behavior_for_collection_types"></a></p>
<h2 id="-collection-">集合(Collection)类型的赋值和拷贝行为</h2>
<p>Swift 中<code>数组(Array)</code><code>字典(Dictionary)</code>类型均以结构体的形式实现。然而当数组被赋予一个常量或变量,或被传递给一个函数或方法时,其拷贝行为与字典和其它结构体有些许不同。</p>
<p>以下对<code>数组</code><code>结构体</code>的行为描述与对<code>NSArray</code><code>NSDictionary</code>的行为描述在本质上不同,后者是以类的形式实现,前者是以结构体的形式实现。<code>NSArray</code><code>NSDictionary</code>实例总是以对已有实例引用,而不是拷贝的方式被赋值和传递。</p>
<blockquote>
<p>以下是对于数组,字典,字符串和其它值的<code>拷贝</code>的描述。
<p>注意:</p>
<p>以下是对于数组,字典,字符串和其它值的<code>拷贝</code>的描述。
在你的代码中拷贝好像是确实是在有拷贝行为的地方产生过。然而在Swift 的后台中,只有确有必要,<code>实际(actual)</code>拷贝才会被执行。Swift 管理所有的值拷贝以确保性能最优化的性能,所以你也没有必要去避免赋值以保证最优性能。(实际赋值由系统管理优化)</p>
</blockquote>
<h3 id="-">字典类型的赋值和拷贝行为</h3>
<p>无论何时将一个<code>字典</code>实例赋给一个常量或变量,或者传递给一个函数或方法,这个字典会即会在赋值或调用发生时被拷贝。在章节<a href="http://" target="_blank">Structures and Enumerations Are Value Types</a>中将会对此过程进行详细介绍。</p>
<p>无论何时将一个<code>字典</code>实例赋给一个常量或变量,或者传递给一个函数或方法,这个字典会即会在赋值或调用发生时被拷贝。在章节<a href="#structures_and_enumerations_are_value_types">结构体和枚举是值类型</a>中将会对此过程进行详细介绍。</p>
<p>如果<code>字典</code>实例中所储存的键(keys)和/或值(values)是值类型(结构体或枚举),当赋值或调用发生时,它们都会被拷贝。相反,如果键(keys)和/或值(values)是引用类型,被拷贝的将会是引用,而不是被它们引用的类实例或函数。<code>字典</code>的键和值的拷贝行为与结构体所储存的属性的拷贝行为相同。</p>
<p>下面的示例定义了一个名为<code>ages</code>的字典,其中储存了四个人的名字和年龄。<code>ages</code>字典被赋予了一个名为<code>copiedAges</code>的新变量,同时<code>ages</code>在赋值的过程中被拷贝。赋值结束后,<code>ages</code><code>copiedAges</code>成为两个相互独立的字典。</p>
<pre><code>var ages = [&quot;Peter&quot;: 23, &quot;Wei&quot;: 35, &quot;Anish&quot;: 65, &quot;Katya&quot;: 19]
@ -776,11 +790,11 @@ var copiedAges = ages
<p>我们可以通过改变一个字典中的年龄值(age value),检查另一个字典中所对应的值,来证明<code>ages</code>字典确实是被拷贝了。如果在<code>copiedAges</code>字典中将<code>Peter</code>的值设为<code>24</code>,那么<code>ages</code>字典仍然会返回修改前的值<code>23</code></p>
<pre><code>copiedAges[&quot;Peter&quot;] = 24
println(ages[&quot;Peter&quot;])
// prints &quot;23&quot;
// 输出 &quot;23&quot;
</code></pre><h3 id="-">数组的赋值和拷贝行为</h3>
<p>在Swift 中,<code>数组(Arrays)</code>类型的赋值和拷贝行为要比<code>字典(Dictionary)</code>类型的复杂的多。当操作数组内容时,<code>数组(Array)</code>能提供接近C语言的的性能并且拷贝行为只有在必要时才会发生。</p>
<p>如果你将一个<code>数组(Array)</code>实例赋给一个变量或常量,或者将其作为参数传递给函数或方法调用,在事件发生时数组的内容<code></code>会被拷贝。相反,数组公用相同的元素序列。当你在一个数组内修改某一元素,修改结果也会在另一数组显示。</p>
<p>对数组来说,拷贝行为仅仅当操作有可能修改数组<code>长度</code>时才会发生。这种行为包括了附加(appending),插入(inserting),删除(removing)或者使用范围下标(ranged subscript)去替换这一范围内的元素。只有当数组拷贝确要发生时,数组内容的行为规则与字典中键值的相同,参见章节<a href="http://" target="_blank">Assignment and Copy Behavior for Dictionaries</a></p>
<p>对数组来说,拷贝行为仅仅当操作有可能修改数组<code>长度</code>时才会发生。这种行为包括了附加(appending),插入(inserting),删除(removing)或者使用范围下标(ranged subscript)去替换这一范围内的元素。只有当数组拷贝确要发生时,数组内容的行为规则与字典中键值的相同,参见章节[集合collection类型的赋值与复制行为](#assignment_and_copy_behavior_for_collection_types</p>
<p>下面的示例将一个<code>整数(Int)</code>数组赋给了一个名为<code>a</code>的变量,继而又被赋给了变量<code>b</code><code>c</code></p>
<pre><code>var a = [1, 2, 3]
var b = a
@ -801,7 +815,7 @@ println(b[0])
println(c[0])
// 42
</code></pre><p>然而,当你给<code>a</code>附加新元素时,数组的长度<code></code>改变。
当附加元素这一事件发生时Swift 语言会创建这个数组的一个拷贝。从此以后,<code>a</code>将会是原数组的一个独立拷贝。</p>
当附加元素这一事件发生时Swift 会创建这个数组的一个拷贝。从此以后,<code>a</code>将会是原数组的一个独立拷贝。</p>
<p>拷贝发生后,如果再修改<code>a</code>中元素值的话,<code>a</code>将会返回与<code>b</code><code>c</code>不同的结果,因为后两者引用的是原来的数组:</p>
<pre><code>a.append(4)
a[0] = 777
@ -833,14 +847,14 @@ println(c[0])
println(&quot;b and c now refer to two independent sets of array elements.&quot;)
}
// prints &quot;b and c now refer totwo independent sets of array elements.&quot;
// 输出 &quot;b and c now refer totwo independent sets of array elements.&quot;
</code></pre><p>此外,我们还可以使用恒等运算符来判定两个子数组是否共用相同的元素。下面这个示例中,比较了<code>b</code>的两个相等的子数组,并且确定了这两个子数组都引用相同的元素:</p>
<pre><code>if b[0...1] === b[0...1] {
println(&quot;These two subarrays share the same elements.&quot;)
} else {
println(&quot;These two subarrays do not share the same elements.&quot;)
}
// prints &quot;These two subarrays share the same elements.&quot;
// 输出 &quot;These two subarrays share the same elements.&quot;
</code></pre><h3 id="-">强制复制数组</h3>
<p>我们通过调用数组的<code>copy</code>方法进行强制显性复制。这个方法对数组进行了浅拷贝(shallow copy),并且返回一个包含此拷贝的新数组。</p>
<p>下面这个示例中定义了一个<code>names</code>数组,其包含了七个人名。还定义了一个<code>copiedNames</code>变量,用以储存在<code>names</code>上调用<code>copy</code>方法所返回的结果:</p>
@ -849,8 +863,9 @@ var copiedNames = names.copy
</code></pre><p>我们可以通过修改一个数组中某元素,并且检查另一个数组中对应元素的方法来判定<code>names</code>数组确已被复制。如果你将<code>copiedNames</code>中第一个元素从&quot;<code>Mohsen</code>&quot;修改为&quot;<code>Mo</code>&quot;,则<code>names</code>数组返回的仍是拷贝发生前的&quot;<code>Mohsen</code>&quot;</p>
<pre><code>copiedName[0] = &quot;Mo&quot;
println(name[0])
// prints &quot;Mohsen&quot;
// 输出 &quot;Mohsen&quot;
</code></pre><blockquote>
<p>注意:</p>
<p>如果你仅需要确保你对数组的引用是唯一引用,请调用<code>unshare</code>方法,而不是<code>copy</code>方法。<code>unshare</code>方法仅会在确有必要时才会创建数组拷贝。<code>copy</code>方法会在任何时候都创建一个新的拷贝,即使引用已经是唯一引用。</p>
</blockquote>
@ -898,6 +913,6 @@ require(["gitbook"], function(gitbook) {
</script>
<script src="http://s19.cnzz.com/z_stat.php?id=1000480711&web_id=1000480711" language="JavaScript"></script></body>
</body>
</html>