make gitbook
This commit is contained in:
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="2.1" data-basepath=".." data-revision="1402617910282">
|
||||
<div class="book" data-level="2.1" data-basepath=".." data-revision="1402634093001">
|
||||
<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>
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="2.2" data-basepath=".." data-revision="1402617910282">
|
||||
<div class="book" data-level="2.2" data-basepath=".." data-revision="1402634093001">
|
||||
<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>
|
||||
@ -748,7 +748,7 @@ a += 2 // a 现在是 3
|
||||
<p>所有标准 C 语言中的比较运算都可以在 Swift 中使用。</p>
|
||||
<ul>
|
||||
<li>等于(<code>a == b</code>)</li>
|
||||
<li>不等于(<code>a!= b</code>)</li>
|
||||
<li>不等于(<code>a != b</code>)</li>
|
||||
<li>大于(<code>a > b</code>)</li>
|
||||
<li>小于(<code>a < b</code>)</li>
|
||||
<li>大于等于(<code>a >= b</code>)</li>
|
||||
@ -778,7 +778,7 @@ if name == "world" {
|
||||
<p>关于<code>if</code>语句,请看<a href="05_Control_Flow.html">控制流</a>。</p>
|
||||
<p><a name="ternary_conditional_operator"></a></p>
|
||||
<h2 id="-ternary-conditional-operator-">三元条件运算(Ternary Conditional Operator)</h2>
|
||||
<p>三元条件运算的特殊在于它是有三个操作数的运算符,它的原型是<code>问题?答案1:答案2</code>。它简洁地表达根据<code>问题</code>成立与否作出二选一的操作。如果<code>问题</code>成立,返回<code>答案1</code>的结果; 如果不成立,返回<code>答案2</code>的结果。</p>
|
||||
<p>三元条件运算的特殊在于它是有三个操作数的运算符,它的原型是 <code>问题 ? 答案1 : 答案2</code>。它简洁地表达根据<code>问题</code>成立与否作出二选一的操作。如果<code>问题</code>成立,返回<code>答案1</code>的结果; 如果不成立,返回<code>答案2</code>的结果。</p>
|
||||
<p>使用三元条件运算简化了以下代码:</p>
|
||||
<pre><code class="lang-swift">if question: {
|
||||
answer1
|
||||
@ -855,7 +855,7 @@ if !allowedEntry {
|
||||
}
|
||||
// 输出 "ACCESS DENIED"
|
||||
</code></pre>
|
||||
<p><code>if!allowedEntry</code>语句可以读作 "如果 非 alowed entry。",接下一行代码只有在如果 "非 allow entry" 为<code>true</code>,即<code>allowEntry</code>为<code>false</code>时被执行。</p>
|
||||
<p><code>if !allowedEntry</code>语句可以读作 "如果 非 alowed entry。",接下一行代码只有在如果 "非 allow entry" 为<code>true</code>,即<code>allowEntry</code>为<code>false</code>时被执行。</p>
|
||||
<p>在示例代码中,小心地选择布尔常量或变量有助于代码的可读性,并且避免使用双重逻辑非运算,或混乱的逻辑语句。</p>
|
||||
<h3 id="-">逻辑与</h3>
|
||||
<p>逻辑与(<code>a && b</code>)表达了只有<code>a</code>和<code>b</code>的值都为<code>true</code>时,整个表达式的值才会是<code>true</code>。</p>
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="2.3" data-basepath=".." data-revision="1402617910282">
|
||||
<div class="book" data-level="2.3" data-basepath=".." data-revision="1402634093001">
|
||||
<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>
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="2.4" data-basepath=".." data-revision="1402617910282">
|
||||
<div class="book" data-level="2.4" data-basepath=".." data-revision="1402634093001">
|
||||
<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>
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="2.5" data-basepath=".." data-revision="1402617910282">
|
||||
<div class="book" data-level="2.5" data-basepath=".." data-revision="1402634093001">
|
||||
<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>
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="2.6" data-basepath=".." data-revision="1402617910282">
|
||||
<div class="book" data-level="2.6" data-basepath=".." data-revision="1402634093001">
|
||||
<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>
|
||||
@ -611,58 +611,64 @@
|
||||
<p>当你定义一个函数时,你可以定义一个或多个有名字和类型的值,作为函数的输入(称为参数,parameters),也可以定义某种类型的值作为函数执行结束的输出(称为返回类型)。</p>
|
||||
<p>每个函数有个函数名,用来描述函数执行的任务。要使用一个函数时,你用函数名“调用”,并传给它匹配的输入值(称作实参,arguments)。一个函数的实参必须与函数参数表里参数的顺序一致。</p>
|
||||
<p>在下面例子中的函数叫做<code>"greetingForPerson"</code>,之所以叫这个名字是因为这个函数用一个人的名字当做输入,并返回给这个人的问候语。为了完成这个任务,你定义一个输入参数-一个叫做 <code>personName</code> 的 <code>String</code> 值,和一个包含给这个人问候语的 <code>String</code> 类型的返回值:</p>
|
||||
<pre><code>func sayHello(personName: String) -> String {
|
||||
<pre><code class="lang-swift">func sayHello(personName: String) -> String {
|
||||
let greeting = "Hello, " + personName + "!"
|
||||
return greeting
|
||||
}
|
||||
</code></pre><p>所有的这些信息汇总起来成为函数的定义,并以 <code>func</code> 作为前缀。指定函数返回类型时,用返回箭头 <code>-></code>(一个连字符后跟一个右尖括号)后跟返回类型的名称的方式来表示。</p>
|
||||
</code></pre>
|
||||
<p>所有的这些信息汇总起来成为函数的定义,并以 <code>func</code> 作为前缀。指定函数返回类型时,用返回箭头 <code>-></code>(一个连字符后跟一个右尖括号)后跟返回类型的名称的方式来表示。</p>
|
||||
<p>该定义描述了函数做什么,它期望接收什么和执行结束时它返回的结果是什么。这样的定义使的函数可以在别的地方以一种清晰的方式被调用:</p>
|
||||
<pre><code>println(sayHello("Anna"))
|
||||
<pre><code class="lang-swift">println(sayHello("Anna"))
|
||||
// prints "Hello, Anna!"
|
||||
println(sayHello("Brian"))
|
||||
// prints "Hello, Brian!
|
||||
</code></pre><p>调用 <code>sayHello</code> 函数时,在圆括号中传给它一个 <code>String</code> 类型的实参。因为这个函数返回一个 <code>String</code> 类型的值,<code>sayHello</code> 可以被包含在 <code>println</code> 的调用中,用来输出这个函数的返回值,正如上面所示。</p>
|
||||
</code></pre>
|
||||
<p>调用 <code>sayHello</code> 函数时,在圆括号中传给它一个 <code>String</code> 类型的实参。因为这个函数返回一个 <code>String</code> 类型的值,<code>sayHello</code> 可以被包含在 <code>println</code> 的调用中,用来输出这个函数的返回值,正如上面所示。</p>
|
||||
<p>在 <code>sayHello</code> 的函数体中,先定义了一个新的名为 <code>greeting</code> 的 <code>String</code> 常量,同时赋值了给 <code>personName</code> 的一个简单问候消息。然后用 <code>return</code> 关键字把这个问候返回出去。一旦 <code>return greeting</code> 被调用,该函数结束它的执行并返回 <code>greeting</code> 的当前值。</p>
|
||||
<p>你可以用不同的输入值多次调用 <code>sayHello</code>。上面的例子展示的是用<code>"Anna"</code>和<code>"Brian"</code>调用的结果,该函数分别返回了不同的结果。</p>
|
||||
<p>为了简化这个函数的定义,可以将问候消息的创建和返回写成一句:</p>
|
||||
<pre><code>func sayHelloAgain(personName: String) -> String {
|
||||
<pre><code class="lang-swift">func sayHelloAgain(personName: String) -> String {
|
||||
return "Hello again, " + personName + "!"
|
||||
}
|
||||
println(sayHelloAgain("Anna"))
|
||||
// prints "Hello again, Anna!
|
||||
</code></pre><p><a name="Function_Parameters_and_Return_Values"></a></p>
|
||||
</code></pre>
|
||||
<p><a name="Function_Parameters_and_Return_Values"></a></p>
|
||||
<h2 id="-function-parameters-and-return-values-">函数参数与返回值(Function Parameters and Return Values)</h2>
|
||||
<p>函数参数与返回值在Swift中极为灵活。你可以定义任何类型的函数,包括从只带一个未名参数的简单函数到复杂的带有表达性参数名和不同参数选项的复杂函数。</p>
|
||||
<h3 id="-multiple-input-parameters-">多重输入参数(Multiple Input Parameters)</h3>
|
||||
<p>函数可以有多个输入参数,写在圆括号中,用逗号分隔。</p>
|
||||
<p>下面这个函数用一个半开区间的开始点和结束点,计算出这个范围内包含多少数字:</p>
|
||||
<pre><code>func halfOpenRangeLength(start: Int, end: Int) -> Int {
|
||||
<pre><code class="lang-swift">func halfOpenRangeLength(start: Int, end: Int) -> Int {
|
||||
return end - start
|
||||
}
|
||||
println(halfOpenRangeLength(1, 10))
|
||||
// prints "9
|
||||
</code></pre><h3 id="-functions-without-parameters-">无参函数(Functions Without Parameters)</h3>
|
||||
</code></pre>
|
||||
<h3 id="-functions-without-parameters-">无参函数(Functions Without Parameters)</h3>
|
||||
<p>函数可以没有参数。下面这个函数就是一个无参函数,当被调用时,它返回固定的 <code>String</code> 消息:</p>
|
||||
<pre><code>func sayHelloWorld() -> String {
|
||||
<pre><code class="lang-swift">func sayHelloWorld() -> String {
|
||||
return "hello, world"
|
||||
}
|
||||
println(sayHelloWorld())
|
||||
// prints "hello, world
|
||||
</code></pre><p>尽管这个函数没有参数,但是定义中在函数名后还是需要一对圆括号。当被调用时,也需要在函数名后写一对圆括号。</p>
|
||||
</code></pre>
|
||||
<p>尽管这个函数没有参数,但是定义中在函数名后还是需要一对圆括号。当被调用时,也需要在函数名后写一对圆括号。</p>
|
||||
<h3 id="-functions-without-return-values-">无返回值函数(Functions Without Return Values)</h3>
|
||||
<p>函数可以没有返回值。下面是 <code>sayHello</code> 函数的另一个版本,叫 <code>waveGoodbye</code>,这个函数直接输出 <code>String</code> 值,而不是返回它:</p>
|
||||
<pre><code>func sayGoodbye(personName: String) {
|
||||
<pre><code class="lang-swift">func sayGoodbye(personName: String) {
|
||||
println("Goodbye, \(personName)!")
|
||||
}
|
||||
sayGoodbye("Dave")
|
||||
// prints "Goodbye, Dave!
|
||||
</code></pre><p>因为这个函数不需要返回值,所以这个函数的定义中没有返回箭头(->)和返回类型。</p>
|
||||
</code></pre>
|
||||
<p>因为这个函数不需要返回值,所以这个函数的定义中没有返回箭头(->)和返回类型。</p>
|
||||
<blockquote>
|
||||
<p>注意:</p>
|
||||
<p>严格上来说,虽然没有返回值被定义,<code>sayGoodbye</code> 函数依然返回了值。没有定义返回类型的函数会返回特殊的值,叫 <code>Void</code>。它其实是一个空的元组(tuple),没有任何元素,可以写成<code>()</code>。</p>
|
||||
</blockquote>
|
||||
<p>被调用时,一个函数的返回值可以被忽略:</p>
|
||||
<pre><code>func printAndCount(stringToPrint: String) -> Int {
|
||||
<pre><code class="lang-swift">func printAndCount(stringToPrint: String) -> Int {
|
||||
println(stringToPrint)
|
||||
return countElements(stringToPrint)
|
||||
}
|
||||
@ -673,7 +679,8 @@ printAndCount("hello, world")
|
||||
// prints "hello, world" and returns a value of 12
|
||||
printWithoutCounting("hello, world")
|
||||
// prints "hello, world" but does not return a value
|
||||
</code></pre><p>第一个函数 <code>printAndCount</code>,输出一个字符串并返回 <code>Int</code> 类型的字符数。第二个函数 <code>printWithoutCounting</code>调用了第一个函数,但是忽略了它的返回值。当第二个函数被调用时,消息依然会由第一个函数输出,但是返回值不会被用到。</p>
|
||||
</code></pre>
|
||||
<p>第一个函数 <code>printAndCount</code>,输出一个字符串并返回 <code>Int</code> 类型的字符数。第二个函数 <code>printWithoutCounting</code>调用了第一个函数,但是忽略了它的返回值。当第二个函数被调用时,消息依然会由第一个函数输出,但是返回值不会被用到。</p>
|
||||
<blockquote>
|
||||
<p>注意:</p>
|
||||
<p>返回值可以被忽略,但定义了有返回值的函数必须返回一个值,如果在函数定义底部没有返回任何值,这叫导致编译错误(compile-time error)。</p>
|
||||
@ -681,7 +688,7 @@ printWithoutCounting("hello, world")
|
||||
<h3 id="-functions-with-multiple-return-values-">多重返回值函数(Functions with Multiple Return Values)</h3>
|
||||
<p>你可以用元组(tuple)类型让多个值作为一个复合值从函数中返回。</p>
|
||||
<p>下面的这个例子中,<code>count</code> 函数用来计算一个字符串中元音,辅音和其他字母的个数(基于美式英语的标准)。</p>
|
||||
<pre><code>func count(string: String) -> (vowels: Int, consonants: Int, others: Int) {
|
||||
<pre><code class="lang-swift">func count(string: String) -> (vowels: Int, consonants: Int, others: Int) {
|
||||
var vowels = 0, consonants = 0, others = 0
|
||||
for character in string {
|
||||
switch String(character).lowercaseString {
|
||||
@ -696,7 +703,8 @@ printWithoutCounting("hello, world")
|
||||
}
|
||||
return (vowels, consonants, others)
|
||||
}
|
||||
</code></pre><p>你可以用 <code>count</code> 函数来处理任何一个字符串,返回的值将是一个包含三个 <code>Int</code> 型值的元组(tuple):</p>
|
||||
</code></pre>
|
||||
<p>你可以用 <code>count</code> 函数来处理任何一个字符串,返回的值将是一个包含三个 <code>Int</code> 型值的元组(tuple):</p>
|
||||
<pre><code>let total = count("some arbitrary string!")
|
||||
println("\(total.vowels) vowels and \(total.consonants) consonants")
|
||||
// prints "6 vowels and 13 consonants
|
||||
@ -704,38 +712,44 @@ println("\(total.vowels) vowels and \(total.consonants) consonants")
|
||||
<a name="Function_Parameter_Names"></a></p>
|
||||
<h2 id="-function-parameter-names-">函数参数名称(Function Parameter Names)</h2>
|
||||
<p>以上所有的函数都给它们的参数定义了<code>参数名(parameter name)</code>:</p>
|
||||
<pre><code>func someFunction(parameterName: Int) {
|
||||
<pre><code class="lang-swift">func someFunction(parameterName: Int) {
|
||||
// function body goes here, and can use parameterName
|
||||
// to refer to the argument value for that parameter
|
||||
}
|
||||
</code></pre><p>但是,这些参数名仅在函数体中使用,不能在函数调用时使用。这种类型的参数名被称作<code>局部参数名(local parameter name)</code>,因为它们只能在函数体中使用。</p>
|
||||
</code></pre>
|
||||
<p>但是,这些参数名仅在函数体中使用,不能在函数调用时使用。这种类型的参数名被称作<code>局部参数名(local parameter name)</code>,因为它们只能在函数体中使用。</p>
|
||||
<h3 id="-external-parameter-names-">外部参数名(External Parameter Names)</h3>
|
||||
<p>有时候,调用函数时,给每个参数命名是非常有用的,因为这些参数名可以指出各个实参的用途是什么。</p>
|
||||
<p>如果你希望函数的使用者在调用函数时提供参数名字,那就需要给每个参数除了局部参数名外再定义一个<code>外部参数名</code>。外部参数名写在局部参数名之前,用空格分隔。</p>
|
||||
<pre><code>func someFunction(externalParameterName localParameterName: Int) {
|
||||
<pre><code class="lang-swift">func someFunction(externalParameterName localParameterName: Int) {
|
||||
// function body goes here, and can use localParameterName
|
||||
// to refer to the argument value for that parameter
|
||||
}
|
||||
</code></pre><blockquote>
|
||||
</code></pre>
|
||||
<blockquote>
|
||||
<p>注意:</p>
|
||||
<p>如果你提供了外部参数名,那么函数在被调用时,必须使用外部参数名。</p>
|
||||
</blockquote>
|
||||
<p>以下是个例子,这个函数使用一个<code>结合者(joiner)</code>把两个字符串联在一起:</p>
|
||||
<pre><code>func join(s1: String, s2: String, joiner: String) -> String {
|
||||
<pre><code class="lang-swift">func join(s1: String, s2: String, joiner: String) -> String {
|
||||
return s1 + joiner + s2
|
||||
}
|
||||
</code></pre><p>当你调用这个函数时,这三个字符串的用途是不清楚的:</p>
|
||||
<pre><code>join("hello", "world", ", ")
|
||||
</code></pre>
|
||||
<p>当你调用这个函数时,这三个字符串的用途是不清楚的:</p>
|
||||
<pre><code class="lang-swift">join("hello", "world", ", ")
|
||||
// returns "hello, world
|
||||
</code></pre><p>为了让这些字符串的用途更为明显,我们为 <code>join</code> 函数添加外部参数名:</p>
|
||||
<pre><code>func join(string s1: String, toString s2: String, withJoiner joiner: String) -> String {
|
||||
</code></pre>
|
||||
<p>为了让这些字符串的用途更为明显,我们为 <code>join</code> 函数添加外部参数名:</p>
|
||||
<pre><code class="lang-swift">func join(string s1: String, toString s2: String, withJoiner joiner: String) -> String {
|
||||
return s1 + joiner + s2
|
||||
}
|
||||
</code></pre><p>在这个版本的 <code>join</code> 函数中,第一个参数有一个叫 <code>string</code> 的外部参数名和 <code>s1</code> 的局部参数名,第二个参数有一个叫 <code>toString</code> 的外部参数名和 <code>s2</code> 的局部参数名,第三个参数有一个叫 <code>withJoiner</code> 的外部参数名和 <code>joiner</code> 的局部参数名。</p>
|
||||
</code></pre>
|
||||
<p>在这个版本的 <code>join</code> 函数中,第一个参数有一个叫 <code>string</code> 的外部参数名和 <code>s1</code> 的局部参数名,第二个参数有一个叫 <code>toString</code> 的外部参数名和 <code>s2</code> 的局部参数名,第三个参数有一个叫 <code>withJoiner</code> 的外部参数名和 <code>joiner</code> 的局部参数名。</p>
|
||||
<p>现在,你可以使用这些外部参数名以一种清晰地方式来调用函数了:</p>
|
||||
<pre><code>join(string: "hello", toString: "world", withJoiner: ", ")
|
||||
<pre><code class="lang-swift">join(string: "hello", toString: "world", withJoiner: ", ")
|
||||
// returns "hello, world
|
||||
</code></pre><p>使用外部参数名让第二个版本的 <code>join</code> 函数的调用更为有表现力,更为通顺,同时还保持了函数体是可读的和有明确意图的。</p>
|
||||
</code></pre>
|
||||
<p>使用外部参数名让第二个版本的 <code>join</code> 函数的调用更为有表现力,更为通顺,同时还保持了函数体是可读的和有明确意图的。</p>
|
||||
<blockquote>
|
||||
<p>注意:</p>
|
||||
<p>当其他人在第一次读你的代码,函数参数的意图显得不明显时,考虑使用外部参数名。如果函数参数名的意图是很明显的,那就不需要定义外部参数名了。</p>
|
||||
@ -743,7 +757,7 @@ println("\(total.vowels) vowels and \(total.consonants) consonants")
|
||||
<h3 id="-shorthand-external-parameter-names-">简写外部参数名(Shorthand External Parameter Names)</h3>
|
||||
<p>如果你需要提供外部参数名,但是局部参数名已经定义好了,那么你不需要写两次这些参数名。相反,只写一次参数名,并用<code>井号(#)</code>作为前缀就可以了。这告诉 Swift 使用这个参数名作为局部和外部参数名。</p>
|
||||
<p>下面这个例子定义了一个叫 <code>containsCharacter</code> 的函数,使用<code>井号(#)</code>的方式定义了外部参数名:</p>
|
||||
<pre><code>func containsCharacter(#string: String, #characterToFind: Character) -> Bool {
|
||||
<pre><code class="lang-swift">func containsCharacter(#string: String, #characterToFind: Character) -> Bool {
|
||||
for character in string {
|
||||
if character == characterToFind {
|
||||
return true
|
||||
@ -751,36 +765,43 @@ println("\(total.vowels) vowels and \(total.consonants) consonants")
|
||||
}
|
||||
return false
|
||||
}
|
||||
</code></pre><p>这样定义参数名,使得函数体更为可读,清晰,同时也可以以一个不含糊的方式被调用:</p>
|
||||
<pre><code>let containsAVee = containsCharacter(string: "aardvark", characterToFind: "v")
|
||||
</code></pre>
|
||||
<p>这样定义参数名,使得函数体更为可读,清晰,同时也可以以一个不含糊的方式被调用:</p>
|
||||
<pre><code class="lang-swift">let containsAVee = containsCharacter(string: "aardvark", characterToFind: "v")
|
||||
// containsAVee equals true, because "aardvark" contains a "v”
|
||||
</code></pre><h3 id="-default-parameter-values-">默认参数值(Default Parameter Values)</h3>
|
||||
</code></pre>
|
||||
<h3 id="-default-parameter-values-">默认参数值(Default Parameter Values)</h3>
|
||||
<p>你可以在函数体中为每个参数定义<code>默认值</code>。当默认值被定义后,调用这个函数时可以略去这个参数。</p>
|
||||
<blockquote>
|
||||
<p>注意:</p>
|
||||
<p>将带有默认值的参数放在函数参数表的最后。这样可以保证在函数调用时,非默认参数的顺序是一致的,同时使得相同的函数在不同情况下调用时显得更为清晰。</p>
|
||||
</blockquote>
|
||||
<p>以下是另一个版本的<code>join</code>函数,其中<code>joiner</code>有了默认参数值:</p>
|
||||
<pre><code>func join(string s1: String, toString s2: String, withJoiner joiner: String = " ") -> String {
|
||||
<pre><code class="lang-swift">func join(string s1: String, toString s2: String, withJoiner joiner: String = " ") -> String {
|
||||
return s1 + joiner + s2
|
||||
}
|
||||
</code></pre><p>像第一个版本的 <code>join</code> 函数一样,如果 <code>joiner</code> 被赋值时,函数将使用这个字符串值来连接两个字符串:</p>
|
||||
<pre><code>join(string: "hello", toString: "world", withJoiner: "-")
|
||||
</code></pre>
|
||||
<p>像第一个版本的 <code>join</code> 函数一样,如果 <code>joiner</code> 被赋值时,函数将使用这个字符串值来连接两个字符串:</p>
|
||||
<pre><code class="lang-swift">join(string: "hello", toString: "world", withJoiner: "-")
|
||||
// returns "hello-world
|
||||
</code></pre><p>当这个函数被调用时,如果 <code>joiner</code> 的值没有被指定,函数会使用默认值(" "):</p>
|
||||
<pre><code>join(string: "hello", toString:"world")
|
||||
</code></pre>
|
||||
<p>当这个函数被调用时,如果 <code>joiner</code> 的值没有被指定,函数会使用默认值(" "):</p>
|
||||
<pre><code class="lang-swift">join(string: "hello", toString:"world")
|
||||
// returns "hello world"
|
||||
</code></pre><h3 id="-external-names-for-parameters-with-default-values-">默认值参数的外部参数名(External Names for Parameters with Default Values)</h3>
|
||||
</code></pre>
|
||||
<h3 id="-external-names-for-parameters-with-default-values-">默认值参数的外部参数名(External Names for Parameters with Default Values)</h3>
|
||||
<p>在大多数情况下,给带默认值的参数起一个外部参数名是很有用的。这样可以保证当函数被调用且带默认值的参数被提供值时,实参的意图是明显的。</p>
|
||||
<p>为了使定义外部参数名更加简单,当你未给带默认值的参数提供外部参数名时,Swift 会自动提供外部名字。此时外部参数名与局部名字是一样的,就像你已经在局部参数名前写了<code>井号(#)</code>一样。</p>
|
||||
<p>下面是 <code>join</code> 函数的另一个版本,这个版本中并没有为它的参数提供外部参数名,但是 <code>joiner</code> 参数依然有外部参数名:</p>
|
||||
<pre><code>func join(s1: String, s2: String, joiner: String = " ") -> String {
|
||||
<pre><code class="lang-swift">func join(s1: String, s2: String, joiner: String = " ") -> String {
|
||||
return s1 + joiner + s2
|
||||
}
|
||||
</code></pre><p>在这个例子中,Swift 自动为 <code>joiner</code> 提供了外部参数名。因此,当函数调用时,外部参数名必须使用,这样使得参数的用途变得清晰。</p>
|
||||
<pre><code>join("hello", "world", joiner: "-")
|
||||
</code></pre>
|
||||
<p>在这个例子中,Swift 自动为 <code>joiner</code> 提供了外部参数名。因此,当函数调用时,外部参数名必须使用,这样使得参数的用途变得清晰。</p>
|
||||
<pre><code class="lang-swift">join("hello", "world", joiner: "-")
|
||||
// returns "hello-world"
|
||||
</code></pre><blockquote>
|
||||
</code></pre>
|
||||
<blockquote>
|
||||
<p>注意:</p>
|
||||
<p>你可以使用<code>下划线(_)</code>作为默认值参数的外部参数名,这样可以在调用时不用提供外部参数名。但是给带默认值的参数命名总是更加合适的。</p>
|
||||
</blockquote>
|
||||
@ -788,7 +809,7 @@ println("\(total.vowels) vowels and \(total.consonants) consonants")
|
||||
<p>一个<code>可变参数(variadic parameter)</code>可以接受一个或多个值。函数调用时,你可以用可变参数来传入不确定数量的输入参数。通过在变量类型名后面加入<code>(...)</code>的方式来定义可变参数。</p>
|
||||
<p>传入可变参数的值在函数体内当做这个类型的一个数组。例如,一个叫做 <code>numbers</code> 的 <code>Double...</code> 型可变参数,在函数体内可以当做一个叫 <code>numbers</code> 的 <code>Double[]</code> 型的数组常量。</p>
|
||||
<p>下面的这个函数用来计算一组任意长度数字的算术平均数:</p>
|
||||
<pre><code>func arithmeticMean(numbers: Double...) -> Double {
|
||||
<pre><code class="lang-swift">func arithmeticMean(numbers: Double...) -> Double {
|
||||
var total: Double = 0
|
||||
for number in numbers {
|
||||
total += number
|
||||
@ -799,7 +820,8 @@ arithmeticMean(1, 2, 3, 4, 5)
|
||||
// returns 3.0, which is the arithmetic mean of these five numbers
|
||||
arithmeticMean(3, 8, 19)
|
||||
// returns 10.0, which is the arithmetic mean of these three numbers
|
||||
</code></pre><blockquote>
|
||||
</code></pre>
|
||||
<blockquote>
|
||||
<p>注意:</p>
|
||||
<p>一个函数至多能有一个可变参数,而且它必须是参数表中最后的一个。这样做是为了避免函数调用时出现歧义。</p>
|
||||
</blockquote>
|
||||
@ -808,7 +830,7 @@ arithmeticMean(3, 8, 19)
|
||||
<p>函数参数默认是常量。试图在函数体中更改参数值将会导致编译错误。这意味着你不能错误地更改参数值。</p>
|
||||
<p>但是,有时候,如果函数中有传入参数的变量值副本将是很有用的。你可以通过指定一个或多个参数为变量参数,从而避免自己在函数中定义新的变量。变量参数不是常量,你可以在函数中把它当做新的可修改副本来使用。</p>
|
||||
<p>通过在参数名前加关键字 <code>var</code> 来定义变量参数:</p>
|
||||
<pre><code>func alignRight(var string: String, count: Int, pad: Character) -> String {
|
||||
<pre><code class="lang-swift">func alignRight(var string: String, count: Int, pad: Character) -> String {
|
||||
let amountToPad = count - countElements(string)
|
||||
for _ in 1...amountToPad {
|
||||
string = pad + string
|
||||
@ -819,7 +841,8 @@ let originalString = "hello"
|
||||
let paddedString = alignRight(originalString, 10, "-")
|
||||
// paddedString is equal to "-----hello"
|
||||
// originalString is still equal to "hello"
|
||||
</code></pre><p>这个例子中定义了一个新的叫做 <code>alignRight</code> 的函数,用来右对齐输入的字符串到一个长的输出字符串中。左侧空余的地方用指定的填充字符填充。这个例子中,字符串<code>"hello"</code>被转换成了<code>"-----hello"</code>。</p>
|
||||
</code></pre>
|
||||
<p>这个例子中定义了一个新的叫做 <code>alignRight</code> 的函数,用来右对齐输入的字符串到一个长的输出字符串中。左侧空余的地方用指定的填充字符填充。这个例子中,字符串<code>"hello"</code>被转换成了<code>"-----hello"</code>。</p>
|
||||
<p><code>alignRight</code> 函数将参数 <code>string</code> 定义为变量参数。这意味着 <code>string</code> 现在可以作为一个局部变量,用传入的字符串值初始化,并且可以在函数体中进行操作。</p>
|
||||
<p>该函数首先计算出多少个字符需要被添加到 <code>string</code> 的左边,以右对齐到总的字符串中。这个值存在局部常量 <code>amountToPad</code> 中。这个函数然后将 <code>amountToPad</code> 多的填充(pad)字符填充到 <code>string</code> 左边,并返回结果。它使用了 <code>string</code> 这个变量参数来进行所有字符串操作。</p>
|
||||
<blockquote>
|
||||
@ -835,19 +858,21 @@ let paddedString = alignRight(originalString, 10, "-")
|
||||
<p>输入输出参数不能有默认值,而且可变参数不能用 <code>inout</code> 标记。如果你用 <code>inout</code> 标记一个参数,这个参数不能被 <code>var</code> 或者 <code>let</code> 标记。</p>
|
||||
</blockquote>
|
||||
<p>下面是例子,<code>swapTwoInts</code> 函数,有两个分别叫做 <code>a</code> 和 <code>b</code> 的输出输出参数:</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>这个 <code>swapTwoInts</code> 函数仅仅交换 <code>a</code> 与 <code>b</code> 的值。该函数先将 <code>a</code> 的值存到一个暂时常量 <code>temporaryA</code> 中,然后将 <code>b</code> 的值赋给 <code>a</code>,最后将 <code>temporaryA</code> 幅值给 <code>b</code>。</p>
|
||||
</code></pre>
|
||||
<p>这个 <code>swapTwoInts</code> 函数仅仅交换 <code>a</code> 与 <code>b</code> 的值。该函数先将 <code>a</code> 的值存到一个暂时常量 <code>temporaryA</code> 中,然后将 <code>b</code> 的值赋给 <code>a</code>,最后将 <code>temporaryA</code> 幅值给 <code>b</code>。</p>
|
||||
<p>你可以用两个 <code>Int</code> 型的变量来调用 <code>swapTwoInts</code>。需要注意的是,<code>someInt</code> 和 <code>anotherInt</code> 在传入 <code>swapTwoInts</code> 函数前,都加了 <code>&</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)")
|
||||
// prints "someInt is now 107, and anotherInt is now 3”
|
||||
</code></pre><p>从上面这个例子中,我们可以看到 <code>someInt</code> 和 <code>anotherInt</code> 的原始值在 <code>swapTwoInts</code> 函数中被修改,尽管它们的定义在函数体外。</p>
|
||||
</code></pre>
|
||||
<p>从上面这个例子中,我们可以看到 <code>someInt</code> 和 <code>anotherInt</code> 的原始值在 <code>swapTwoInts</code> 函数中被修改,尽管它们的定义在函数体外。</p>
|
||||
<blockquote>
|
||||
<p>注意:</p>
|
||||
<p>输出输出参数和返回值是不一样的。上面的 <code>swapTwoInts</code> 函数并没有定义任何返回值,但仍然修改了 <code>someInt</code> 和 <code>anotherInt</code> 的值。输入输出参数是函数对函数体外产生影响的另一种方式。
|
||||
@ -856,66 +881,76 @@ println("someInt is now \(someInt), and anotherInt is now \(anotherInt)&quo
|
||||
</blockquote>
|
||||
<p>每个函数都有种特定的函数类型,由函数的参数类型和返回类型组成。</p>
|
||||
<p>例如:</p>
|
||||
<pre><code>func addTwoInts(a: Int, b: Int) -> Int {
|
||||
<pre><code class="lang-swift">func addTwoInts(a: Int, b: Int) -> Int {
|
||||
return a + b
|
||||
}
|
||||
func multiplyTwoInts(a: Int, b: Int) -> Int {
|
||||
return a * b
|
||||
}
|
||||
</code></pre><p>这个例子中定义了两个简单的数学函数:<code>addTwoInts</code> 和 <code>multiplyTwoInts</code>。这两个函数都传入两个 <code>Int</code> 类型, 返回一个合适的<code>Int</code>值。</p>
|
||||
</code></pre>
|
||||
<p>这个例子中定义了两个简单的数学函数:<code>addTwoInts</code> 和 <code>multiplyTwoInts</code>。这两个函数都传入两个 <code>Int</code> 类型, 返回一个合适的<code>Int</code>值。</p>
|
||||
<p>这两个函数的类型是 <code>(Int, Int) -> Int</code>,可以读作“这个函数类型,它有两个 <code>Int</code> 型的参数并返回一个 <code>Int</code> 型的值。”。</p>
|
||||
<p>下面是另一个例子,一个没有参数,也没有返回值的函数:</p>
|
||||
<pre><code>func printHelloWorld() {
|
||||
<pre><code class="lang-swift">func printHelloWorld() {
|
||||
println("hello, world")
|
||||
}
|
||||
</code></pre><p>这个函数的类型是:<code>() -> ()</code>,或者叫“没有参数,并返回 <code>Void</code> 类型的函数。”。没有指定返回类型的函数总返回 <code>Void</code>。在Swift中,<code>Void</code> 与空的元组是一样的。</p>
|
||||
</code></pre>
|
||||
<p>这个函数的类型是:<code>() -> ()</code>,或者叫“没有参数,并返回 <code>Void</code> 类型的函数。”。没有指定返回类型的函数总返回 <code>Void</code>。在Swift中,<code>Void</code> 与空的元组是一样的。</p>
|
||||
<h3 id="-using-function-types-">使用函数类型(Using Function Types)</h3>
|
||||
<p>在Swift中,使用函数类型就像使用其他类型一样。例如,你可以定义一个类型为函数的常量或变量,并将函数赋值给它:</p>
|
||||
<pre><code>var mathFunction: (Int, Int) -> Int = addTwoInts
|
||||
</code></pre><p>这个可以读作:</p>
|
||||
<pre><code class="lang-swift">var mathFunction: (Int, Int) -> Int = addTwoInts
|
||||
</code></pre>
|
||||
<p>这个可以读作:</p>
|
||||
<p>“定义一个叫做 <code>mathFunction</code> 的变量,类型是‘一个有两个 <code>Int</code> 型的参数并返回一个 <code>Int</code> 型的值的函数’,并让这个新变量指向 <code>addTwoInts</code> 函数”。</p>
|
||||
<p><code>addTwoInts</code> 和 <code>mathFunction</code> 有同样的类型,所以这个赋值过程在 Swift 类型检查中是允许的。</p>
|
||||
<p>现在,你可以用 <code>mathFunction</code> 来调用被赋值的函数了:</p>
|
||||
<pre><code>println("Result: \(mathFunction(2, 3))")
|
||||
<pre><code class="lang-swift">println("Result: \(mathFunction(2, 3))")
|
||||
// prints "Result: 5
|
||||
</code></pre><p>有相同匹配类型的不同函数可以被赋值给同一个变量,就像非函数类型的变量一样:</p>
|
||||
<pre><code>mathFunction = multiplyTwoInts
|
||||
</code></pre>
|
||||
<p>有相同匹配类型的不同函数可以被赋值给同一个变量,就像非函数类型的变量一样:</p>
|
||||
<pre><code class="lang-swift">mathFunction = multiplyTwoInts
|
||||
println("Result: \(mathFunction(2, 3))")
|
||||
// prints "Result: 6"
|
||||
</code></pre><p>就像其他类型一样,当赋值一个函数给常量或变量时,你可以让 Swift 来推测其函数类型:</p>
|
||||
<pre><code>let anotherMathFunction = addTwoInts
|
||||
</code></pre>
|
||||
<p>就像其他类型一样,当赋值一个函数给常量或变量时,你可以让 Swift 来推测其函数类型:</p>
|
||||
<pre><code class="lang-swift">let anotherMathFunction = addTwoInts
|
||||
// anotherMathFunction is inferred to be of type (Int, Int) -> Int
|
||||
</code></pre><h3 id="-function-types-as-parameter-types-">函数类型作为参数类型(Function Types as Parameter Types)</h3>
|
||||
</code></pre>
|
||||
<h3 id="-function-types-as-parameter-types-">函数类型作为参数类型(Function Types as Parameter Types)</h3>
|
||||
<p>你可以用<code>(Int, Int) -> Int</code>这样的函数类型作为另一个函数的参数类型。这样你可以将函数的一部分实现交由给函数的调用者。</p>
|
||||
<p>下面是另一个例子,正如上面的函数一样,同样是输出某种数学运算结果:</p>
|
||||
<pre><code>func printMathResult(mathFunction: (Int, Int) -> Int, a: Int, b: Int) {
|
||||
<pre><code class="lang-swift">func printMathResult(mathFunction: (Int, Int) -> Int, a: Int, b: Int) {
|
||||
println("Result: \(mathFunction(a, b))")
|
||||
}
|
||||
printMathResult(addTwoInts, 3, 5)
|
||||
// prints "Result: 8”
|
||||
</code></pre><p>这个例子定义了 <code>printMathResult</code> 函数,它有三个参数:第一个参数叫 <code>mathFunction</code>,类型是<code>(Int, Int) -> Int</code>,你可以传入任何这种类型的函数;第二个和第三个参数叫 <code>a</code> 和 <code>b</code>,它们的类型都是 <code>Int</code>,这两个值作为已给的函数的输入值。</p>
|
||||
</code></pre>
|
||||
<p>这个例子定义了 <code>printMathResult</code> 函数,它有三个参数:第一个参数叫 <code>mathFunction</code>,类型是<code>(Int, Int) -> Int</code>,你可以传入任何这种类型的函数;第二个和第三个参数叫 <code>a</code> 和 <code>b</code>,它们的类型都是 <code>Int</code>,这两个值作为已给的函数的输入值。</p>
|
||||
<p>当 <code>printMathResult</code> 被调用时,它被传入 <code>addTwoInts</code> 函数和整数<code>3</code>和<code>5</code>。它用传入<code>3</code>和<code>5</code>调用 <code>addTwoInts</code>,并输出结果:<code>8</code>。</p>
|
||||
<p><code>printMathResult</code> 函数的作用就是输出另一个合适类型的数学函数的调用结果。它不关心传入函数是如何实现的,它只关心这个传入的函数类型是正确的。这使得 <code>printMathResult</code> 可以以一种类型安全(type-safe)的方式来保证传入函数的调用是正确的。</p>
|
||||
<h3 id="-function-type-as-return-types-">函数类型作为返回类型(Function Type as Return Types)</h3>
|
||||
<p>你可以用函数类型作为另一个函数的返回类型。你需要做的是在返回箭头(<code>-></code>)后写一个完整的函数类型。</p>
|
||||
<p>下面的这个例子中定义了两个简单函数,分别是 <code>stepForward</code> 和<code>stepBackward</code>。<code>stepForward</code> 函数返回一个比输入值大一的值。<code>stepBackward</code> 函数返回一个比输入值小一的值。这两个函数的类型都是 <code>(Int) -> Int</code>:</p>
|
||||
<pre><code>func stepForward(input: Int) -> Int {
|
||||
<pre><code class="lang-swift">func stepForward(input: Int) -> Int {
|
||||
return input + 1
|
||||
}
|
||||
func stepBackward(input: Int) -> Int {
|
||||
return input - 1
|
||||
}
|
||||
</code></pre><p>下面这个叫做 <code>chooseStepFunction</code> 的函数,它的返回类型是 <code>(Int) -> Int</code> 的函数。<code>chooseStepFunction</code> 根据布尔值 <code>backwards</code> 来返回 <code>stepForward</code> 函数或 <code>stepBackward</code> 函数:</p>
|
||||
<pre><code>func chooseStepFunction(backwards: Bool) -> (Int) -> Int {
|
||||
</code></pre>
|
||||
<p>下面这个叫做 <code>chooseStepFunction</code> 的函数,它的返回类型是 <code>(Int) -> Int</code> 的函数。<code>chooseStepFunction</code> 根据布尔值 <code>backwards</code> 来返回 <code>stepForward</code> 函数或 <code>stepBackward</code> 函数:</p>
|
||||
<pre><code class="lang-swift">func chooseStepFunction(backwards: Bool) -> (Int) -> Int {
|
||||
return backwards ? stepBackward : stepForward
|
||||
}
|
||||
</code></pre><p>你现在可以用 <code>chooseStepFunction</code> 来获得一个函数,不管是那个方向:</p>
|
||||
<pre><code>var currentValue = 3
|
||||
</code></pre>
|
||||
<p>你现在可以用 <code>chooseStepFunction</code> 来获得一个函数,不管是那个方向:</p>
|
||||
<pre><code class="lang-swift">var currentValue = 3
|
||||
let moveNearerToZero = chooseStepFunction(currentValue > 0)
|
||||
// moveNearerToZero now refers to the stepBackward() function
|
||||
</code></pre><p>上面这个例子中计算出从 <code>currentValue</code> 逐渐接近到<code>0</code>是需要向正数走还是向负数走。<code>currentValue</code> 的初始值是<code>3</code>,这意味着 <code>currentValue > 0</code> 是真的(<code>true</code>),这将使得 <code>chooseStepFunction</code> 返回 <code>stepBackward</code> 函数。一个指向返回的函数的引用保存在了 <code>moveNearerToZero</code> 常量中。</p>
|
||||
</code></pre>
|
||||
<p>上面这个例子中计算出从 <code>currentValue</code> 逐渐接近到<code>0</code>是需要向正数走还是向负数走。<code>currentValue</code> 的初始值是<code>3</code>,这意味着 <code>currentValue > 0</code> 是真的(<code>true</code>),这将使得 <code>chooseStepFunction</code> 返回 <code>stepBackward</code> 函数。一个指向返回的函数的引用保存在了 <code>moveNearerToZero</code> 常量中。</p>
|
||||
<p>现在,<code>moveNearerToZero</code> 指向了正确的函数,它可以被用来数到<code>0</code>:</p>
|
||||
<pre><code>println("Counting to zero:")
|
||||
<pre><code class="lang-swift">println("Counting to zero:")
|
||||
// Counting to zero:
|
||||
while currentValue != 0 {
|
||||
println("\(currentValue)... ")
|
||||
@ -926,12 +961,13 @@ println("zero!")
|
||||
// 2...
|
||||
// 1...
|
||||
// zero!
|
||||
</code></pre><p><a name="Nested_Functions"></a></p>
|
||||
</code></pre>
|
||||
<p><a name="Nested_Functions"></a></p>
|
||||
<h2 id="-nested-functions-">嵌套函数(Nested Functions)</h2>
|
||||
<p>这章中你所见到的所有函数都叫全局函数(global functions),它们定义在全局域中。你也可以把函数定义在别的函数体中,称作嵌套函数(nested functions)。</p>
|
||||
<p>默认情况下,嵌套函数是对外界不可见的,但是可以被他们封闭函数(enclosing function)来调用。一个封闭函数也可以返回它的某一个嵌套函数,使得这个函数可以在其他域中被使用。</p>
|
||||
<p>你可以用返回嵌套函数的方式重写 <code>chooseStepFunction</code> 函数:</p>
|
||||
<pre><code>func chooseStepFunction(backwards: Bool) -> (Int) -> Int {
|
||||
<pre><code class="lang-swift">func chooseStepFunction(backwards: Bool) -> (Int) -> Int {
|
||||
func stepForward(input: Int) -> Int { return input + 1 }
|
||||
func stepBackward(input: Int) -> Int { return input - 1 }
|
||||
return backwards ? stepBackward : stepForward
|
||||
@ -950,6 +986,7 @@ println("zero!")
|
||||
// -1...
|
||||
// zero!
|
||||
</code></pre>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="2.7" data-basepath=".." data-revision="1402617910282">
|
||||
<div class="book" data-level="2.7" data-basepath=".." data-revision="1402634093001">
|
||||
<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>
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="2.8" data-basepath=".." data-revision="1402617910282">
|
||||
<div class="book" data-level="2.8" data-basepath=".." data-revision="1402634093001">
|
||||
<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>
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="2.9" data-basepath=".." data-revision="1402617910282">
|
||||
<div class="book" data-level="2.9" data-basepath=".." data-revision="1402634093001">
|
||||
<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>
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="2.10" data-basepath=".." data-revision="1402617910282">
|
||||
<div class="book" data-level="2.10" data-basepath=".." data-revision="1402634093001">
|
||||
<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>
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="2.11" data-basepath=".." data-revision="1402617910282">
|
||||
<div class="book" data-level="2.11" data-basepath=".." data-revision="1402634093001">
|
||||
<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>
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="2.12" data-basepath=".." data-revision="1402617910282">
|
||||
<div class="book" data-level="2.12" data-basepath=".." data-revision="1402634093001">
|
||||
<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>
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="2.13" data-basepath=".." data-revision="1402617910282">
|
||||
<div class="book" data-level="2.13" data-basepath=".." data-revision="1402634093001">
|
||||
<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>
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="2.14" data-basepath=".." data-revision="1402617910282">
|
||||
<div class="book" data-level="2.14" data-basepath=".." data-revision="1402634093001">
|
||||
<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>
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="2.15" data-basepath=".." data-revision="1402617910282">
|
||||
<div class="book" data-level="2.15" data-basepath=".." data-revision="1402634093001">
|
||||
<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>
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="2.16" data-basepath=".." data-revision="1402617910282">
|
||||
<div class="book" data-level="2.16" data-basepath=".." data-revision="1402634093001">
|
||||
<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>
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="2.17" data-basepath=".." data-revision="1402617910282">
|
||||
<div class="book" data-level="2.17" data-basepath=".." data-revision="1402634093001">
|
||||
<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>
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="2.18" data-basepath=".." data-revision="1402617910282">
|
||||
<div class="book" data-level="2.18" data-basepath=".." data-revision="1402634093001">
|
||||
<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>
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="2.19" data-basepath=".." data-revision="1402617910282">
|
||||
<div class="book" data-level="2.19" data-basepath=".." data-revision="1402634093001">
|
||||
<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>
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="2.20" data-basepath=".." data-revision="1402617910282">
|
||||
<div class="book" data-level="2.20" data-basepath=".." data-revision="1402634093001">
|
||||
<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>
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="2.21" data-basepath=".." data-revision="1402617910282">
|
||||
<div class="book" data-level="2.21" data-basepath=".." data-revision="1402634093001">
|
||||
<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>
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="2.22" data-basepath=".." data-revision="1402617910282">
|
||||
<div class="book" data-level="2.22" data-basepath=".." data-revision="1402634093001">
|
||||
<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>
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
|
||||
<div class="book" data-level="2.23" data-basepath=".." data-revision="1402617910282">
|
||||
<div class="book" data-level="2.23" data-basepath=".." data-revision="1402634093001">
|
||||
<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>
|
||||
@ -615,32 +615,36 @@
|
||||
<p>按位取反运算符<code>~</code>对一个操作数的每一位都取反。</p>
|
||||
<p><img src="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/bitwiseNOT_2x.png" alt="Art/bitwiseNOT_2x.png" title="Art/bitwiseNOT_2x.png"></p>
|
||||
<p>这个运算符是前置的,所以请不加任何空格地写着操作数之前。</p>
|
||||
<pre><code>let initialBits: UInt8 = 0b00001111
|
||||
<pre><code class="lang-swift">let initialBits: UInt8 = 0b00001111
|
||||
let invertedBits = ~initialBits // 等于 0b11110000
|
||||
</code></pre><p><code>UInt8</code>是8位无符整型,可以存储0~255之间的任意数。这个例子初始化一个整型为二进制值<code>00001111</code>(前4位为<code>0</code>,后4位为<code>1</code>),它的十进制值为<code>15</code>。</p>
|
||||
</code></pre>
|
||||
<p><code>UInt8</code>是8位无符整型,可以存储0~255之间的任意数。这个例子初始化一个整型为二进制值<code>00001111</code>(前4位为<code>0</code>,后4位为<code>1</code>),它的十进制值为<code>15</code>。</p>
|
||||
<p>使用按位取反运算<code>~</code>对<code>initialBits</code>操作,然后赋值给<code>invertedBits</code>这个新常量。这个新常量的值等于所有位都取反的<code>initialBits</code>,即<code>1</code>变成<code>0</code>,<code>0</code>变成<code>1</code>,变成了<code>11110000</code>,十进制值为<code>240</code>。</p>
|
||||
<h3 id="-">按位与运算符</h3>
|
||||
<p>按位与运算符对两个数进行操作,然后返回一个新的数,这个数的每个位都需要两个输入数的同一位都为1时才为1。</p>
|
||||
<p><img src="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/bitwiseAND_2x.png" alt="Art/bitwiseAND_2x.png" title="Art/bitwiseAND_2x.png"></p>
|
||||
<p>以下代码,<code>firstSixBits</code>和<code>lastSixBits</code>中间4个位都为1。对它俩进行按位与运算后,就得到了<code>00111100</code>,即十进制的<code>60</code>。</p>
|
||||
<pre><code>let firstSixBits: UInt8 = 0b11111100
|
||||
<pre><code class="lang-swift">let firstSixBits: UInt8 = 0b11111100
|
||||
let lastSixBits: UInt8 = 0b00111111
|
||||
let middleFourBits = firstSixBits & lastSixBits // 等于 00111100
|
||||
</code></pre><h3 id="-">按位或运算</h3>
|
||||
</code></pre>
|
||||
<h3 id="-">按位或运算</h3>
|
||||
<p>按位或运算符<code>|</code>比较两个数,然后返回一个新的数,这个数的每一位设置1的条件是两个输入数的同一位都不为0(即任意一个为1,或都为1)。</p>
|
||||
<p><img src="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/bitwiseOR_2x.png" alt="Art/bitwiseOR_2x.png" title="Art/bitwiseOR_2x.png"></p>
|
||||
<p>如下代码,<code>someBits</code>和<code>moreBits</code>在不同位上有<code>1</code>。按位或运行的结果是<code>11111110</code>,即十进制的<code>254</code>。</p>
|
||||
<pre><code>let someBits: UInt8 = 0b10110010
|
||||
<pre><code class="lang-swift">let someBits: UInt8 = 0b10110010
|
||||
let moreBits: UInt8 = 0b01011110
|
||||
let combinedbits = someBits | moreBits // 等于 11111110
|
||||
</code></pre><h3 id="-">按位异或运算符</h3>
|
||||
</code></pre>
|
||||
<h3 id="-">按位异或运算符</h3>
|
||||
<p>按位异或运算符<code>^</code>比较两个数,然后返回一个数,这个数的每个位设为<code>1</code>的条件是两个输入数的同一位不同,如果相同就设为<code>0</code>。</p>
|
||||
<p><img src="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/bitwiseXOR_2x.png" alt="Art/bitwiseXOR_2x.png" title="Art/bitwiseXOR_2x.png"></p>
|
||||
<p>以下代码,<code>firstBits</code>和<code>otherBits</code>都有一个<code>1</code>跟另一个数不同的。所以按位异或的结果是把它这些位置为<code>1</code>,其他都置为<code>0</code>。</p>
|
||||
<pre><code>let firstBits: UInt8 = 0b00010100
|
||||
<pre><code class="lang-swift">let firstBits: UInt8 = 0b00010100
|
||||
let otherBits: UInt8 = 0b00000101
|
||||
let outputBits = firstBits ^ otherBits // 等于 00010001
|
||||
</code></pre><h3 id="-">按位左移/右移运算符</h3>
|
||||
</code></pre>
|
||||
<h3 id="-">按位左移/右移运算符</h3>
|
||||
<p>左移运算符<code><<</code>和右移运算符<code>>></code>会把一个数的所有比特位按以下定义的规则向左或向右移动指定位数。</p>
|
||||
<p>按位左移和按位右移的效果相当把一个整数乘于或除于一个因子为<code>2</code>的整数。向左移动一个整型的比特位相当于把这个数乘于<code>2</code>,向右移一位就是除于<code>2</code>。</p>
|
||||
<h4 id="-">无符整型的移位操作</h4>
|
||||
@ -648,18 +652,20 @@ let outputBits = firstBits ^ otherBits // 等于 00010001
|
||||
<p>已经存在的比特位向左或向右移动指定的位数。被移出整型存储边界的的位数直接抛弃,移动留下的空白位用零<code>0</code>来填充。这种方法称为逻辑移位。</p>
|
||||
<p>以下这张把展示了 <code>11111111 << 1</code>(<code>11111111</code>向左移1位),和 <code>11111111 >> 1</code>(<code>11111111</code>向右移1位)。蓝色的是被移位的,灰色是被抛弃的,橙色的<code>0</code>是被填充进来的。</p>
|
||||
<p><img src="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/bitshiftUnsigned_2x.png" alt="Art/bitshiftUnsigned_2x.png" title="Art/bitshiftUnsigned_2x.png"></p>
|
||||
<pre><code>let shiftBits: UInt8 = 4 // 即二进制的00000100
|
||||
<pre><code class="lang-swift">let shiftBits: UInt8 = 4 // 即二进制的00000100
|
||||
shiftBits << 1 // 00001000
|
||||
shiftBits << 2 // 00010000
|
||||
shiftBits << 5 // 10000000
|
||||
shiftBits << 6 // 00000000
|
||||
shiftBits >> 2 // 00000001
|
||||
</code></pre><p>你可以使用移位操作进行其他数据类型的编码和解码。</p>
|
||||
<pre><code>let pink: UInt32 = 0xCC6699
|
||||
</code></pre>
|
||||
<p>你可以使用移位操作进行其他数据类型的编码和解码。</p>
|
||||
<pre><code class="lang-swift">let pink: UInt32 = 0xCC6699
|
||||
let redComponent = (pink & 0xFF0000) >> 16 // redComponent 是 0xCC, 即 204
|
||||
let greenComponent = (pink & 0x00FF00) >> 8 // greenComponent 是 0x66, 即 102
|
||||
let blueComponent = pink & 0x0000FF // blueComponent 是 0x99, 即 153
|
||||
</code></pre><p>这个例子使用了一个<code>UInt32</code>的命名为<code>pink</code>的常量来存储层叠样式表<code>CSS</code>中粉色的颜色值,<code>CSS</code>颜色<code>#CC6699</code>在Swift用十六进制<code>0xCC6699</code>来表示。然后使用按位与(&)和按位右移就可以从这个颜色值中解析出红(CC),绿(66),蓝(99)三个部分。</p>
|
||||
</code></pre>
|
||||
<p>这个例子使用了一个<code>UInt32</code>的命名为<code>pink</code>的常量来存储层叠样式表<code>CSS</code>中粉色的颜色值,<code>CSS</code>颜色<code>#CC6699</code>在Swift用十六进制<code>0xCC6699</code>来表示。然后使用按位与(&)和按位右移就可以从这个颜色值中解析出红(CC),绿(66),蓝(99)三个部分。</p>
|
||||
<p>对<code>0xCC6699</code>和<code>0xFF0000</code>进行按位与<code>&</code>操作就可以得到红色部分。<code>0xFF0000</code>中的<code>0</code>了遮盖了<code>OxCC6699</code>的第二和第三个字节,这样<code>6699</code>被忽略了,只留下<code>0xCC0000</code>。</p>
|
||||
<p>然后,按向右移动16位,即 <code>>> 16</code>。十六进制中每两个字符是8比特位,所以移动16位的结果是把<code>0xCC0000</code>变成<code>0x0000CC</code>。这和<code>0xCC</code>是相等的,都是十进制的<code>204</code>。</p>
|
||||
<p>同样的,绿色部分来自于<code>0xCC6699</code>和<code>0x00FF00</code>的按位操作得到<code>0x006600</code>。然后向右移动8們,得到<code>0x66</code>,即十进制的<code>102</code>。</p>
|
||||
@ -687,11 +693,12 @@ let blueComponent = pink & 0x0000FF // blueComponent 是 0x99, 即
|
||||
<h2 id="-">溢出运算符</h2>
|
||||
<p>默认情况下,当你往一个整型常量或变量赋于一个它不能承载的大数时,Swift不会让你这么干的,它会报错。这样,在操作过大或过小的数的时候就很安全了。</p>
|
||||
<p>例如,<code>Int16</code>整型能承载的整数范围是<code>-32768</code>到<code>32767</code>,如果给它赋上超过这个范围的数,就会报错:</p>
|
||||
<pre><code>var potentialOverflow = Int16.max
|
||||
<pre><code class="lang-swift">var potentialOverflow = Int16.max
|
||||
// potentialOverflow 等于 32767, 这是 Int16 能承载的最大整数
|
||||
potentialOverflow += 1
|
||||
// 噢, 出错了
|
||||
</code></pre><p>对过大或过小的数值进行错误处理让你的数值边界条件更灵活。</p>
|
||||
</code></pre>
|
||||
<p>对过大或过小的数值进行错误处理让你的数值边界条件更灵活。</p>
|
||||
<p>当然,你有意在溢出时对有效位进行截断,你可采用溢出运算,而非错误处理。Swfit为整型计算提供了5个<code>&</code>符号开头的溢出运算符。</p>
|
||||
<ul>
|
||||
<li>溢出加法 <code>&+</code></li>
|
||||
@ -702,44 +709,50 @@ potentialOverflow += 1
|
||||
</ul>
|
||||
<h3 id="-">值的上溢出</h3>
|
||||
<p>下面例子使用了溢出加法<code>&+</code>来解剖的无符整数的上溢出</p>
|
||||
<pre><code>var willOverflow = UInt8.max
|
||||
<pre><code class="lang-swift">var willOverflow = UInt8.max
|
||||
// willOverflow 等于UInt8的最大整数 255
|
||||
willOverflow = willOverflow &+ 1
|
||||
// 这时候 willOverflow 等于 0
|
||||
</code></pre><p><code>willOverflow</code>用<code>Int8</code>所能承载的最大值<code>255</code>(二进制<code>11111111</code>),然后用<code>&+</code>加1。然后<code>UInt8</code>就无法表达这个新值的二进制了,也就导致了这个新值上溢出了,大家可以看下图。溢出后,新值在<code>UInt8</code>的承载范围内的那部分是<code>00000000</code>,也就是<code>0</code>。</p>
|
||||
</code></pre>
|
||||
<p><code>willOverflow</code>用<code>Int8</code>所能承载的最大值<code>255</code>(二进制<code>11111111</code>),然后用<code>&+</code>加1。然后<code>UInt8</code>就无法表达这个新值的二进制了,也就导致了这个新值上溢出了,大家可以看下图。溢出后,新值在<code>UInt8</code>的承载范围内的那部分是<code>00000000</code>,也就是<code>0</code>。</p>
|
||||
<p><img src="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/overflowAddition_2x.png" alt="Art/overflowAddition_2x.png" title="Art/overflowAddition_2x.png"></p>
|
||||
<h3 id="-">值的下溢出</h3>
|
||||
<p>数值也有可能因为太小而越界。举个例子:</p>
|
||||
<p><code>UInt8</code>的最小值是<code>0</code>(二进制为<code>00000000</code>)。使用<code>&-</code>进行溢出减1,就会得到二进制的<code>11111111</code>即十进制的<code>255</code>。</p>
|
||||
<p><img src="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/overflowUnsignedSubtraction_2x.png" alt="Art/overflowUnsignedSubtraction_2x.png" title="Art/overflowUnsignedSubtraction_2x.png"></p>
|
||||
<p>Swift代码是这样的:</p>
|
||||
<pre><code>var willUnderflow = UInt8.min
|
||||
<pre><code class="lang-swift">var willUnderflow = UInt8.min
|
||||
// willUnderflow 等于UInt8的最小值0
|
||||
willUnderflow = willUnderflow &- 1
|
||||
// 此时 willUnderflow 等于 255
|
||||
</code></pre><p>有符整型也有类似的下溢出,有符整型所有的减法也都是对包括在符号位在内的二进制数进行二进制减法的,这在 "按位左移/右移运算符" 一节提到过。最小的有符整数是<code>-128</code>,即二进制的<code>10000000</code>。用溢出减法减去去1后,变成了<code>01111111</code>,即UInt8所能承载的最大整数<code>127</code>。</p>
|
||||
</code></pre>
|
||||
<p>有符整型也有类似的下溢出,有符整型所有的减法也都是对包括在符号位在内的二进制数进行二进制减法的,这在 "按位左移/右移运算符" 一节提到过。最小的有符整数是<code>-128</code>,即二进制的<code>10000000</code>。用溢出减法减去去1后,变成了<code>01111111</code>,即UInt8所能承载的最大整数<code>127</code>。</p>
|
||||
<p><img src="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/overflowSignedSubtraction_2x.png" alt="Art/overflowSignedSubtraction_2x.png" title="Art/overflowSignedSubtraction_2x.png"></p>
|
||||
<p>来看看Swift代码:</p>
|
||||
<pre><code>var signedUnderflow = Int8.min
|
||||
<pre><code class="lang-swift">var signedUnderflow = Int8.min
|
||||
// signedUnderflow 等于最小的有符整数 -128
|
||||
signedUnderflow = signedUnderflow &- 1
|
||||
// 如今 signedUnderflow 等于 127
|
||||
</code></pre><h3 id="-">除零溢出</h3>
|
||||
</code></pre>
|
||||
<h3 id="-">除零溢出</h3>
|
||||
<p>一个数除于0 <code>i / 0</code>,或者对0求余数 <code>i % 0</code>,就会产生一个错误。</p>
|
||||
<pre><code>let x = 1
|
||||
<pre><code class="lang-swift">let x = 1
|
||||
let y = x / 0
|
||||
</code></pre><p>使用它们对应的可溢出的版本的运算符<code>&/</code>和<code>&%</code>进行除0操作时就会得到<code>0</code>值。</p>
|
||||
<pre><code>let x = 1
|
||||
</code></pre>
|
||||
<p>使用它们对应的可溢出的版本的运算符<code>&/</code>和<code>&%</code>进行除0操作时就会得到<code>0</code>值。</p>
|
||||
<pre><code class="lang-swift">let x = 1
|
||||
let y = x &/ 0
|
||||
// y 等于 0
|
||||
</code></pre><p><a name="precedence_and_associativity"></a></p>
|
||||
</code></pre>
|
||||
<p><a name="precedence_and_associativity"></a></p>
|
||||
<h2 id="-">优先级和结合性</h2>
|
||||
<p>运算符的优先级使得一些运算符优先于其他运算符,高优先级的运算符会先被计算。</p>
|
||||
<p>结合性定义相同优先级的运算符在一起时是怎么组合或关联的,是和左边的一组呢,还是和右边的一组。意思就是,到底是和左边的表达式结合呢,还是和右边的表达式结合?</p>
|
||||
<p>在混合表达式中,运算符的优先级和结合性是非常重要的。举个例子,为什么下列表达式的结果为<code>4</code>?</p>
|
||||
<pre><code>2 + 3 * 4 % 5
|
||||
<pre><code class="lang-swift">2 + 3 * 4 % 5
|
||||
// 结果是 4
|
||||
</code></pre><p>如果严格地从左计算到右,计算过程会是这样:</p>
|
||||
</code></pre>
|
||||
<p>如果严格地从左计算到右,计算过程会是这样:</p>
|
||||
<ul>
|
||||
<li>2 plus 3 equals 5;</li>
|
||||
<li>2 + 3 = 5</li>
|
||||
@ -750,14 +763,17 @@ let y = x &/ 0
|
||||
</ul>
|
||||
<p>但是正确答案是<code>4</code>而不是<code>0</code>。优先级高的运算符要先计算,在Swift和C语言中,都是先乘除后加减的。所以,执行完乘法和求余运算才能执行加减运算。</p>
|
||||
<p>乘法和求余拥有相同的优先级,在运算过程中,我们还需要结合性,乘法和求余运算都是左结合的。这相当于在表达式中有隐藏的括号让运算从左开始。</p>
|
||||
<pre><code>2 + ((3 * 4) % 5)
|
||||
</code></pre><p>(3 <em> 4) is 12, so this is equivalent to:
|
||||
<pre><code class="lang-swift">2 + ((3 * 4) % 5)
|
||||
</code></pre>
|
||||
<p>(3 <em> 4) is 12, so this is equivalent to:
|
||||
3 </em> 4 = 12,所以这相当于:</p>
|
||||
<pre><code>2 + (12 % 5)
|
||||
</code></pre><p>(12 % 5) is 2, so this is equivalent to:
|
||||
<pre><code class="lang-swift">2 + (12 % 5)
|
||||
</code></pre>
|
||||
<p>(12 % 5) is 2, so this is equivalent to:
|
||||
12 % 5 = 2,所这又相当于</p>
|
||||
<pre><code>2 + 2
|
||||
</code></pre><p>计算结果为 4。</p>
|
||||
<pre><code class="lang-swift">2 + 2
|
||||
</code></pre>
|
||||
<p>计算结果为 4。</p>
|
||||
<p>查阅Swift运算符的优先级和结合性的完整列表,请看<a href="../chapter3/04_Expressions.html">表达式</a>。</p>
|
||||
<blockquote>
|
||||
<p>注意:</p>
|
||||
@ -768,96 +784,109 @@ let y = x &/ 0
|
||||
<p>让已有的运算符也可以对自定义的类和结构进行运算,这称为运算符重载。</p>
|
||||
<p>这个例子展示了如何用<code>+</code>让一个自定义的结构做加法。算术运算符<code>+</code>是一个两目运算符,因为它有两个操作数,而且它必须出现在两个操作数之间。</p>
|
||||
<p>例子中定义了一个名为<code>Vector2D</code>的二维坐标向量 <code>(x,y)</code> 的结构,然后定义了让两个<code>Vector2D</code>的对象相加的运算符函数。</p>
|
||||
<pre><code>struct Vector2D {
|
||||
<pre><code class="lang-swift">struct Vector2D {
|
||||
var x = 0.0, y = 0.0
|
||||
}
|
||||
@infix func + (left: Vector2D, right: Vector2D) -> Vector2D {
|
||||
return Vector2D(x: left.x + right.x, y: left.y + right.y)
|
||||
}
|
||||
</code></pre><p>该运算符函数定义了一个全局的<code>+</code>函数,这个函数需要两个<code>Vector2D</code>类型的参数,返回值也是<code>Vector2D</code>类型。需要定义和实现一个中置运算的时候,在关键字<code>func</code>之前写上属性 <code>@infix</code> 就可以了。</p>
|
||||
</code></pre>
|
||||
<p>该运算符函数定义了一个全局的<code>+</code>函数,这个函数需要两个<code>Vector2D</code>类型的参数,返回值也是<code>Vector2D</code>类型。需要定义和实现一个中置运算的时候,在关键字<code>func</code>之前写上属性 <code>@infix</code> 就可以了。</p>
|
||||
<p>在这个代码实现中,参数被命名为了<code>left</code>和<code>right</code>,代表<code>+</code>左边和右边的两个<code>Vector2D</code>对象。函数返回了一个新的<code>Vector2D</code>的对象,这个对象的<code>x</code>和<code>y</code>分别等于两个参数对象的<code>x</code>和<code>y</code>的和。</p>
|
||||
<p>这个函数是全局的,而不是<code>Vector2D</code>结构的成员方法,所以任意两个<code>Vector2D</code>对象都可以使用这个中置运算符。</p>
|
||||
<pre><code>let vector = Vector2D(x: 3.0, y: 1.0)
|
||||
<pre><code class="lang-swift">let vector = Vector2D(x: 3.0, y: 1.0)
|
||||
let anotherVector = Vector2D(x: 2.0, y: 4.0)
|
||||
let combinedVector = vector + anotherVector
|
||||
// combinedVector 是一个新的Vector2D, 值为 (5.0, 5.0)
|
||||
</code></pre><p>这个例子实现两个向量 <code>(3.0,1.0)</code> 和 <code>(2.0,4.0)</code> 相加,得到向量 <code>(5.0,5.0)</code> 的过程。如下图示:</p>
|
||||
</code></pre>
|
||||
<p>这个例子实现两个向量 <code>(3.0,1.0)</code> 和 <code>(2.0,4.0)</code> 相加,得到向量 <code>(5.0,5.0)</code> 的过程。如下图示:</p>
|
||||
<p><img src="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/vectorAddition_2x.png" alt="Art/vectorAddition_2x.png" title="Art/vectorAddition_2x.png"></p>
|
||||
<h3 id="-">前置和后置运算符</h3>
|
||||
<p>上个例子演示了一个双目中置运算符的自定义实现,同样我们也可以玩标准单目运算符的实现。单目运算符只有一个操作数,在操作数之前就是前置的,如<code>-a</code>; 在操作数之后就是后置的,如<code>i++</code>。</p>
|
||||
<p>实现一个前置或后置运算符时,在定义该运算符的时候于关键字<code>func</code>之前标注 <code>@prefix</code> 或 <code>@postfix</code> 属性。</p>
|
||||
<pre><code>@prefix func - (vector: Vector2D) -> Vector2D {
|
||||
<pre><code class="lang-swift">@prefix func - (vector: Vector2D) -> Vector2D {
|
||||
return Vector2D(x: -vector.x, y: -vector.y)
|
||||
}
|
||||
</code></pre><p>这段代码为<code>Vector2D</code>类型提供了单目减运算<code>-a</code>,<code>@prefix</code>属性表明这是个前置运算符。</p>
|
||||
</code></pre>
|
||||
<p>这段代码为<code>Vector2D</code>类型提供了单目减运算<code>-a</code>,<code>@prefix</code>属性表明这是个前置运算符。</p>
|
||||
<p>对于数值,单目减运算符可以把正数变负数,把负数变正数。对于<code>Vector2D</code>,单目减运算将其<code>x</code>和<code>y</code>都进进行单目减运算。</p>
|
||||
<pre><code>let positive = Vector2D(x: 3.0, y: 4.0)
|
||||
<pre><code class="lang-swift">let positive = Vector2D(x: 3.0, y: 4.0)
|
||||
let negative = -positive
|
||||
// negative 为 (-3.0, -4.0)
|
||||
let alsoPositive = -negative
|
||||
// alsoPositive 为 (3.0, 4.0)
|
||||
</code></pre><h3 id="-">组合赋值运算符</h3>
|
||||
</code></pre>
|
||||
<h3 id="-">组合赋值运算符</h3>
|
||||
<p>组合赋值是其他运算符和赋值运算符一起执行的运算。如<code>+=</code>把加运算和赋值运算组合成一个操作。实现一个组合赋值符号需要使用<code>@assignment</code>属性,还需要把运算符的左参数设置成<code>inout</code>,因为这个参数会在运算符函数内直接修改它的值。</p>
|
||||
<pre><code>@assignment func += (inout left: Vector2D, right: Vector2D) {
|
||||
<pre><code class="lang-swift">@assignment func += (inout left: Vector2D, right: Vector2D) {
|
||||
left = left + right
|
||||
}
|
||||
</code></pre><p>因为加法运算在之前定义过了,这里无需重新定义。所以,加赋运算符函数使用已经存在的高级加法运算符函数来执行左值加右值的运算。</p>
|
||||
<pre><code>var original = Vector2D(x: 1.0, y: 2.0)
|
||||
</code></pre>
|
||||
<p>因为加法运算在之前定义过了,这里无需重新定义。所以,加赋运算符函数使用已经存在的高级加法运算符函数来执行左值加右值的运算。</p>
|
||||
<pre><code class="lang-swift">var original = Vector2D(x: 1.0, y: 2.0)
|
||||
let vectorToAdd = Vector2D(x: 3.0, y: 4.0)
|
||||
original += vectorToAdd
|
||||
// original 现在为 (4.0, 6.0)
|
||||
</code></pre><p>你可以将 <code>@assignment</code> 属性和 <code>@prefix</code> 或 <code>@postfix</code> 属性起来组合,实现一个<code>Vector2D</code>的前置运算符。</p>
|
||||
<pre><code>@prefix @assignment func ++ (inout vector: Vector2D) -> Vector2D {
|
||||
</code></pre>
|
||||
<p>你可以将 <code>@assignment</code> 属性和 <code>@prefix</code> 或 <code>@postfix</code> 属性起来组合,实现一个<code>Vector2D</code>的前置运算符。</p>
|
||||
<pre><code class="lang-swift">@prefix @assignment func ++ (inout vector: Vector2D) -> Vector2D {
|
||||
vector += Vector2D(x: 1.0, y: 1.0)
|
||||
return vector
|
||||
}
|
||||
</code></pre><p>这个前置使用了已经定义好的高级加赋运算,将自己加上一个值为 <code>(1.0,1.0)</code> 的对象然后赋给自己,然后再将自己返回。</p>
|
||||
<pre><code>var toIncrement = Vector2D(x: 3.0, y: 4.0)
|
||||
</code></pre>
|
||||
<p>这个前置使用了已经定义好的高级加赋运算,将自己加上一个值为 <code>(1.0,1.0)</code> 的对象然后赋给自己,然后再将自己返回。</p>
|
||||
<pre><code class="lang-swift">var toIncrement = Vector2D(x: 3.0, y: 4.0)
|
||||
let afterIncrement = ++toIncrement
|
||||
// toIncrement 现在是 (4.0, 5.0)
|
||||
// afterIncrement 现在也是 (4.0, 5.0)
|
||||
</code></pre><blockquote>
|
||||
</code></pre>
|
||||
<blockquote>
|
||||
<p>注意:</p>
|
||||
<p>默认的赋值符是不可重载的。只有组合赋值符可以重载。三目条件运算符 <code>a?b:c</code> 也是不可重载。</p>
|
||||
</blockquote>
|
||||
<h3 id="-">比较运算符</h3>
|
||||
<p>Swift无所知道自定义类型是否相等或不等,因为等于或者不等于由你的代码说了算了。所以自定义的类和结构要使用比较符<code>==</code>或<code>!=</code>就需要重载。</p>
|
||||
<p>定义相等运算符函数跟定义其他中置运算符雷同:</p>
|
||||
<pre><code>@infix func == (left: Vector2D, right: Vector2D) -> Bool {
|
||||
<pre><code class="lang-swift">@infix func == (left: Vector2D, right: Vector2D) -> Bool {
|
||||
return (left.x == right.x) && (left.y == right.y)
|
||||
}
|
||||
|
||||
@infix func != (left: Vector2D, right: Vector2D) -> Bool {
|
||||
return !(left == right)
|
||||
}
|
||||
</code></pre><p>上述代码实现了相等运算符<code>==</code>来判断两个<code>Vector2D</code>对象是否有相等的值,相等的概念就是他们有相同的<code>x</code>值和相同的<code>y</code>值,我们就用这个逻辑来实现。接着使用<code>==</code>的结果实现了不相等运算符<code>!=</code>。</p>
|
||||
</code></pre>
|
||||
<p>上述代码实现了相等运算符<code>==</code>来判断两个<code>Vector2D</code>对象是否有相等的值,相等的概念就是他们有相同的<code>x</code>值和相同的<code>y</code>值,我们就用这个逻辑来实现。接着使用<code>==</code>的结果实现了不相等运算符<code>!=</code>。</p>
|
||||
<p>现在我们可以使用这两个运算符来判断两个<code>Vector2D</code>对象是否相等。</p>
|
||||
<pre><code>let twoThree = Vector2D(x: 2.0, y: 3.0)
|
||||
<pre><code class="lang-swift">let twoThree = Vector2D(x: 2.0, y: 3.0)
|
||||
let anotherTwoThree = Vector2D(x: 2.0, y: 3.0)
|
||||
if twoThree == anotherTwoThree {
|
||||
println("这两个向量是相等的.")
|
||||
}
|
||||
// prints "这两个向量是相等的."
|
||||
</code></pre><h3 id="-">自定义运算符</h3>
|
||||
</code></pre>
|
||||
<h3 id="-">自定义运算符</h3>
|
||||
<p>标准的运算符不够玩,那你可以声明一些个性的运算符,但个性的运算符只能使用这些字符 <code>/ = - + * % < >!& | ^。~</code>。</p>
|
||||
<p>新的运算符声明需在全局域使用<code>operator</code>关键字声明,可以声明为前置,中置或后置的。</p>
|
||||
<pre><code>operator prefix +++ {}
|
||||
</code></pre><p>这段代码定义了一个新的前置运算符叫<code>+++</code>,此前Swift并不存在这个运算符。此处为了演示,我们让<code>+++</code>对<code>Vector2D</code>对象的操作定义为 <code>双自增</code> 这样一个独有的操作,这个操作使用了之前定义的加赋运算实现了自已加上自己然后返回的运算。</p>
|
||||
<pre><code>@prefix @assignment func +++ (inout vector: Vector2D) -> Vector2D {
|
||||
<pre><code class="lang-swift">operator prefix +++ {}
|
||||
</code></pre>
|
||||
<p>这段代码定义了一个新的前置运算符叫<code>+++</code>,此前Swift并不存在这个运算符。此处为了演示,我们让<code>+++</code>对<code>Vector2D</code>对象的操作定义为 <code>双自增</code> 这样一个独有的操作,这个操作使用了之前定义的加赋运算实现了自已加上自己然后返回的运算。</p>
|
||||
<pre><code class="lang-swift">@prefix @assignment func +++ (inout vector: Vector2D) -> Vector2D {
|
||||
vector += vector
|
||||
return vector
|
||||
}
|
||||
</code></pre><p><code>Vector2D</code> 的 <code>+++</code> 的实现和 <code>++</code> 的实现很接近, 唯一不同的前者是加自己, 后者是加值为 <code>(1.0, 1.0)</code> 的向量.</p>
|
||||
<pre><code>var toBeDoubled = Vector2D(x: 1.0, y: 4.0)
|
||||
</code></pre>
|
||||
<p><code>Vector2D</code> 的 <code>+++</code> 的实现和 <code>++</code> 的实现很接近, 唯一不同的前者是加自己, 后者是加值为 <code>(1.0, 1.0)</code> 的向量.</p>
|
||||
<pre><code class="lang-swift">var toBeDoubled = Vector2D(x: 1.0, y: 4.0)
|
||||
let afterDoubling = +++toBeDoubled
|
||||
// toBeDoubled 现在是 (2.0, 8.0)
|
||||
// afterDoubling 现在也是 (2.0, 8.0)
|
||||
</code></pre><h3 id="-">自定义中置运算符的优先级和结合性</h3>
|
||||
</code></pre>
|
||||
<h3 id="-">自定义中置运算符的优先级和结合性</h3>
|
||||
<p>可以为自定义的中置运算符指定优先级和结合性。可以回头看看<a href="#PrecedenceandAssociativity">优先级和结合性</a>解释这两个因素是如何影响多种中置运算符混合的表达式的计算的。</p>
|
||||
<p>结合性(associativity)的值可取的值有<code>left</code>,<code>right</code>和<code>none</code>。左结合运算符跟其他优先级相同的左结合运算符写在一起时,会跟左边的操作数结合。同理,右结合运算符会跟右边的操作数结合。而非结合运算符不能跟其他相同优先级的运算符写在一起。</p>
|
||||
<p>结合性(associativity)的值默认为<code>none</code>,优先级(precedence)默认为<code>100</code>。</p>
|
||||
<p>以下例子定义了一个新的中置符<code>+-</code>,是左结合的<code>left</code>,优先级为<code>140</code>。</p>
|
||||
<pre><code>operator infix +- { associativity left precedence 140 }
|
||||
<pre><code class="lang-swift">operator infix +- { associativity left precedence 140 }
|
||||
func +- (left: Vector2D, right: Vector2D) -> Vector2D {
|
||||
return Vector2D(x: left.x + right.x, y: left.y - right.y)
|
||||
}
|
||||
@ -865,7 +894,8 @@ let firstVector = Vector2D(x: 1.0, y: 2.0)
|
||||
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>
|
||||
</code></pre>
|
||||
<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="1402617910282">
|
||||
<div class="book" data-level="2" data-basepath=".." data-revision="1402634093001">
|
||||
<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>
|
||||
|
||||
Reference in New Issue
Block a user