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/05_Control_Flow.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.6" data-basepath=".." data-revision="1402493167130">
<div class="book" data-level="2.6" 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,45 +587,51 @@
<div class="page-inner">
<section class="normal" id="section-gitbook_127">
<section class="normal" id="section-gitbook_6481">
<h1 id="-functions-">函数Functions</h1>
<blockquote>
<p>翻译honghaoz</p>
<p>校对LunaticM</p>
</blockquote>
<h1 id="-functions-">函数Functions</h1>
<hr>
<p>本页包含内容:</p>
<ul>
<li>函数定义与调用</li>
<li>函数参数与返回值</li>
<li>函数参数名称</li>
<li>函数类型</li>
<li>函数嵌套</li>
<li><a href="#Defining_and_Calling_Functions">函数定义与调用Defining and Calling Functions</a></li>
<li><a href="#Function_Parameters_and_Return_Values">函数参数与返回值Function Parameters and Return Values</a></li>
<li><a href="#Function_Parameter_Names">函数参数名称Function Parameter Names</a></li>
<li><a href="#Function_Types">函数类型Function Types</a></li>
<li><a href="#Nested_Functions">函数嵌套Nested Functions</a></li>
</ul>
<p>函数是用来完成特定任务的独立的代码块。你给一个函数起一个合适的名字,用来标示函数做什么,并且当函数需要执行的时候,这个名字会被“调用”。</p>
<p>Swift统一的函数语法足够灵活可以用来表示任何函数包括从最简单的没有参数名字的C风格函数到复杂的带局部和外部参数名的Objective-C风格函数。参数可以提供默认值以简化函数调用。参数也可以即当做传入参数也当做传出参数也就是说一旦函数执行结束传入的参数值可以被修改。</p>
<p>在Swift中每个函数都有一种类型包括函数的参数值类型和返回值类型。你可以把函数类型当做任何其他普通变量类型一样处理这样就可以更简单地把函数当做别的函数的参数也可以从其他函数中返回函数。函数的定义可以写在在其他函数定义中这样可以在嵌套函数范围内实现功能封装。</p>
<p>Swift 统一的函数语法足够灵活,可以用来表示任何函数,包括从最简单的没有参数名字的 C 风格函数,到复杂的带局部和外部参数名的 Objective-C 风格函数。参数可以提供默认值,以简化函数调用。参数也可以即当做传入参数,也当做传出参数,也就是说,一旦函数执行结束,传入的参数值可以被修改。</p>
<p> Swift 中,每个函数都有一种类型,包括函数的参数值类型和返回值类型。你可以把函数类型当做任何其他普通变量类型一样处理,这样就可以更简单地把函数当做别的函数的参数,也可以从其他函数中返回函数。函数的定义可以写在在其他函数定义中,这样可以在嵌套函数范围内实现功能封装。
<a name="Defining_and_Calling_Functions"></a></p>
<h2 id="-defining-and-calling-functions-">函数的定义与调用Defining and Calling Functions</h2>
<p>当你定义一个函数时你可以定义一个或多个有名字和类型的值作为函数的输入称为参数parameters也可以定义某种类型的值作为函数执行结束的输出称为返回类型</p>
<p>每个函数有个函数名用来描述函数执行的任务。要使用一个函数时你用函数名“调用”并传给它匹配的输入值称作实参arguments。一个函数的实参必须与函数参数表里参数的顺序一致。</p>
<p>在下面例子中的函数叫做<code>&quot;greetingForPerson&quot;</code>,之所以叫这个名字是因为这个函数用一个人的名字当做输入,并返回给这个人的问候语。为了完成这个任务,你定义一个输入参数-一个叫做<code>personName</code><code>String</code>值,和一个包含给这个人问候语的<code>String</code>类型的返回值:</p>
<p>在下面例子中的函数叫做<code>&quot;greetingForPerson&quot;</code>,之所以叫这个名字是因为这个函数用一个人的名字当做输入,并返回给这个人的问候语。为了完成这个任务,你定义一个输入参数-一个叫做 <code>personName</code><code>String</code> 值,和一个包含给这个人问候语的 <code>String</code> 类型的返回值:</p>
<pre><code>func sayHello(personName: String) -&gt; String {
let greeting = &quot;Hello, &quot; + personName + &quot;!&quot;
return greeting
}
</code></pre><p>所有的这些信息汇总起来成为函数的定义,并以<code>func</code>作为前缀。指定函数返回类型时,用返回箭头<code>-&gt;</code>(一个连字符后跟一个右尖括号)后跟返回类型的名称的方式来表示。</p>
</code></pre><p>所有的这些信息汇总起来成为函数的定义,并以 <code>func</code> 作为前缀。指定函数返回类型时,用返回箭头 <code>-&gt;</code>(一个连字符后跟一个右尖括号)后跟返回类型的名称的方式来表示。</p>
<p>该定义描述了函数做什么,它期望接收什么和执行结束时它返回的结果是什么。这样的定义使的函数可以在别的地方以一种清晰的方式被调用:</p>
<pre><code>println(sayHello(&quot;Anna&quot;))
// prints &quot;Hello, Anna!&quot;
println(sayHello(&quot;Brian&quot;))
// prints &quot;Hello, Brian!
</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>&quot;Anna&quot;</code><code>&quot;Brian&quot;</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>&quot;Anna&quot;</code><code>&quot;Brian&quot;</code>调用的结果,该函数分别返回了不同的结果。</p>
<p>为了简化这个函数的定义,可以将问候消息的创建和返回写成一句:</p>
<pre><code>func sayHelloAgain(personName: String) -&gt; String {
return &quot;Hello again, &quot; + personName + &quot;!&quot;
}
println(sayHelloAgain(&quot;Anna&quot;))
// prints &quot;Hello again, Anna!
</code></pre><h2 id="-function-parameters-and-return-values-">函数参数与返回值Function Parameters and Return Values</h2>
</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>
@ -636,7 +642,7 @@ println(sayHelloAgain(&quot;Anna&quot;))
println(halfOpenRangeLength(1, 10))
// prints &quot;9
</code></pre><h3 id="-functions-without-parameters-">无参函数Functions Without Parameters</h3>
<p>函数可以没有参数。下面这个函数就是一个无参函数,当被调用时,它返回固定的<code>String</code>消息:</p>
<p>函数可以没有参数。下面这个函数就是一个无参函数,当被调用时,它返回固定的 <code>String</code> 消息:</p>
<pre><code>func sayHelloWorld() -&gt; String {
return &quot;hello, world&quot;
}
@ -644,7 +650,7 @@ println(sayHelloWorld())
// prints &quot;hello, world
</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>
<p>函数可以没有返回值。下面是 <code>sayHello</code> 函数的另一个版本,叫 <code>waveGoodbye</code>,这个函数直接输出 <code>String</code> 值,而不是返回它:</p>
<pre><code>func sayGoodbye(personName: String) {
println(&quot;Goodbye, \(personName)!&quot;)
}
@ -652,8 +658,8 @@ sayGoodbye(&quot;Dave&quot;)
// prints &quot;Goodbye, Dave!
</code></pre><p>因为这个函数不需要返回值,所以这个函数的定义中没有返回箭头(-&gt;)和返回类型。</p>
<blockquote>
<p>注意:
严格上来说,虽然没有返回值被定义,<code>sayGoodbye</code>函数依然返回了值。没有定义返回类型的函数会返回特殊的值,叫<code>Void</code>。它其实是一个空的元组tuple没有任何元素可以写成<code>()</code></p>
<p>注意:</p>
<p>严格上来说,虽然没有返回值被定义,<code>sayGoodbye</code> 函数依然返回了值。没有定义返回类型的函数会返回特殊的值,叫 <code>Void</code>。它其实是一个空的元组tuple没有任何元素可以写成<code>()</code></p>
</blockquote>
<p>被调用时,一个函数的返回值可以被忽略:</p>
<pre><code>func printAndCount(stringToPrint: String) -&gt; Int {
@ -667,14 +673,14 @@ printAndCount(&quot;hello, world&quot;)
// prints &quot;hello, world&quot; and returns a value of 12
printWithoutCounting(&quot;hello, world&quot;)
// prints &quot;hello, world&quot; 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>注意:
返回值可以被忽略但定义了有返回值的函数必须返回一个值如果在函数定义底部没有返回任何值这叫导致编译错误compile-time error</p>
<p>注意:</p>
<p>返回值可以被忽略但定义了有返回值的函数必须返回一个值如果在函数定义底部没有返回任何值这叫导致编译错误compile-time error</p>
</blockquote>
<h3 id="-functions-with-multiple-return-values-">多重返回值函数Functions with Multiple Return Values</h3>
<p>你可以用元组tuple类型让多个值作为一个复合值从函数中返回。</p>
<p>下面的这个例子中,<code>count</code>函数用来计算一个字符串中元音,辅音和其他字母的个数(基于美式英语的标准)。</p>
<p>下面的这个例子中,<code>count</code> 函数用来计算一个字符串中元音,辅音和其他字母的个数(基于美式英语的标准)。</p>
<pre><code>func count(string: String) -&gt; (vowels: Int, consonants: Int, others: Int) {
var vowels = 0, consonants = 0, others = 0
for character in string {
@ -690,12 +696,13 @@ printWithoutCounting(&quot;hello, world&quot;)
}
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(&quot;some arbitrary string!&quot;)
println(&quot;\(total.vowels) vowels and \(total.consonants) consonants&quot;)
// prints &quot;6 vowels and 13 consonants
</code></pre><p>需要注意的是,元组的成员不需要在函数中返回时命名,因为它们的名字已经在函数返回类型有有了定义。</p>
<h2 id="-function-parameter-names-">函数参数名Function Parameter Names</h2>
</code></pre><p>需要注意的是,元组的成员不需要在函数中返回时命名,因为它们的名字已经在函数返回类型有有了定义。
<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) {
// function body goes here, and can use parameterName
@ -710,8 +717,8 @@ println(&quot;\(total.vowels) vowels and \(total.consonants) consonants&quot;)
// to refer to the argument value for that parameter
}
</code></pre><blockquote>
<p>注意:
如果你提供了外部参数名,那么函数在被调用时,必须使用外部参数名。</p>
<p>注意:</p>
<p>如果你提供了外部参数名,那么函数在被调用时,必须使用外部参数名。</p>
</blockquote>
<p>以下是个例子,这个函数使用一个<code>结合者joiner</code>把两个字符串联在一起:</p>
<pre><code>func join(s1: String, s2: String, joiner: String) -&gt; String {
@ -720,22 +727,22 @@ println(&quot;\(total.vowels) vowels and \(total.consonants) consonants&quot;)
</code></pre><p>当你调用这个函数时,这三个字符串的用途是不清楚的:</p>
<pre><code>join(&quot;hello&quot;, &quot;world&quot;, &quot;, &quot;)
// returns &quot;hello, world
</code></pre><p>为了让这些字符串的用途更为明显,我们为<code>join</code>函数添加外部参数名:</p>
</code></pre><p>为了让这些字符串的用途更为明显,我们为 <code>join</code> 函数添加外部参数名:</p>
<pre><code>func join(string s1: String, toString s2: String, withJoiner joiner: String) -&gt; 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: &quot;hello&quot;, toString: &quot;world&quot;, withJoiner: &quot;, &quot;)
// returns &quot;hello, world
</code></pre><p>使用外部参数名让第二个版本的<code>join</code>函数的调用更为有表现力,更为通顺,同时还保持了函数体是可读的和有明确意图的。</p>
</code></pre><p>使用外部参数名让第二个版本的 <code>join</code> 函数的调用更为有表现力,更为通顺,同时还保持了函数体是可读的和有明确意图的。</p>
<blockquote>
<p>注意:
当其他人在第一次读你的代码,函数参数的意图显得不明显时,考虑使用外部参数名。如果函数参数名的意图是很明显的,那就不需要定义外部参数名了。</p>
<p>注意:</p>
<p>当其他人在第一次读你的代码,函数参数的意图显得不明显时,考虑使用外部参数名。如果函数参数名的意图是很明显的,那就不需要定义外部参数名了。</p>
</blockquote>
<h3 id="-shorthand-external-parameter-names-">简写外部参数名Shorthand External Parameter Names</h3>
<p>如果你需要提供外部参数名,但是局部参数名已经定义好了,那么你不需要写两次这些参数名。相反,只写一次参数名,并用<code>井号(#</code>作为前缀就可以了。这告诉Swift使用这个参数名作为局部和外部参数名。</p>
<p>下面这个例子定义了一个叫<code>containsCharacter</code>的函数,使用<code>井号(#</code>的方式定义了外部参数名:</p>
<p>如果你需要提供外部参数名,但是局部参数名已经定义好了,那么你不需要写两次这些参数名。相反,只写一次参数名,并用<code>井号(#</code>作为前缀就可以了。这告诉 Swift 使用这个参数名作为局部和外部参数名。</p>
<p>下面这个例子定义了一个叫 <code>containsCharacter</code> 的函数,使用<code>井号(#</code>的方式定义了外部参数名:</p>
<pre><code>func containsCharacter(#string: String, #characterToFind: Character) -&gt; Bool {
for character in string {
if character == characterToFind {
@ -750,36 +757,36 @@ println(&quot;\(total.vowels) vowels and \(total.consonants) consonants&quot;)
</code></pre><h3 id="-default-parameter-values-">默认参数值Default Parameter Values</h3>
<p>你可以在函数体中为每个参数定义<code>默认值</code>。当默认值被定义后,调用这个函数时可以略去这个参数。</p>
<blockquote>
<p>注意:
将带有默认值的参数放在函数参数表的最后。这样可以保证在函数调用时,非默认参数的顺序是一致的,同时使得相同的函数在不同情况下调用时显得更为清晰。</p>
<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 = &quot; &quot;) -&gt; String {
return s1 + joiner + s2
}
</code></pre><p>像第一个版本的<code>join</code>函数一样,如果<code>joiner</code>被幅值时,函数将使用这个字符串值来连接两个字符串:</p>
</code></pre><p>像第一个版本的 <code>join</code> 函数一样,如果 <code>joiner</code> 被赋值时,函数将使用这个字符串值来连接两个字符串:</p>
<pre><code>join(string: &quot;hello&quot;, toString: &quot;world&quot;, withJoiner: &quot;-&quot;)
// returns &quot;hello-world
</code></pre><p>当这个函数被调用时,如果<code>joiner</code>的值没有被指定,函数会使用默认值(&quot; &quot;</p>
</code></pre><p>当这个函数被调用时,如果 <code>joiner</code> 的值没有被指定,函数会使用默认值(&quot; &quot;</p>
<pre><code>join(string: &quot;hello&quot;, toString:&quot;world&quot;)
// returns &quot;hello world&quot;
</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>
<p>为了使定义外部参数名更加简单当你未给带默认值的参数提供外部参数名时Swift 会自动提供外部名字。此时外部参数名与局部名字是一样的,就像你已经在局部参数名前写了<code>井号(#</code>一样。</p>
<p>下面是 <code>join</code> 函数的另一个版本,这个版本中并没有为它的参数提供外部参数名,但是 <code>joiner</code> 参数依然有外部参数名:</p>
<pre><code>func join(s1: String, s2: String, joiner: String = &quot; &quot;) -&gt; String {
return s1 + joiner + s2
}
</code></pre><p>在这个例子中Swift自动为<code>joiner</code>提供了外部参数名。因此,当函数调用时,外部参数名必须使用,这样使得参数的用途变得清晰。</p>
</code></pre><p>在这个例子中Swift 自动为 <code>joiner</code> 提供了外部参数名。因此,当函数调用时,外部参数名必须使用,这样使得参数的用途变得清晰。</p>
<pre><code>join(&quot;hello&quot;, &quot;world&quot;, joiner: &quot;-&quot;)
// returns &quot;hello-world&quot;
</code></pre><blockquote>
<p>注意:
你可以使用<code>下划线_</code>作为默认值参数的外部参数名,这样可以在调用时不用提供外部参数名。但是给带默认值的参数命名总是更加合适的。</p>
<p>注意:</p>
<p>你可以使用<code>下划线_</code>作为默认值参数的外部参数名,这样可以在调用时不用提供外部参数名。但是给带默认值的参数命名总是更加合适的。</p>
</blockquote>
<h3 id="-variadic-parameters-">可变参数Variadic Parameters</h3>
<p>一个<code>可变参数variadic parameter</code>可以接受一个或多个值。函数调用时,你可以用可变参数来传入不确定数量的输入参数。通过在变量类型名后面加入<code>...</code>的方式来定义可变参数。</p>
<p>传入可变参数的值在函数体内当做这个类型的一个数组。例如,一个叫做<code>numbers</code><code>Double...</code>型可变参数,在函数体内可以当做一个叫<code>numbers</code><code>Double[]</code>型的数组常量。</p>
<p>传入可变参数的值在函数体内当做这个类型的一个数组。例如,一个叫做 <code>numbers</code><code>Double...</code> 型可变参数,在函数体内可以当做一个叫 <code>numbers</code><code>Double[]</code> 型的数组常量。</p>
<p>下面的这个函数用来计算一组任意长度数字的算术平均数:</p>
<pre><code>func arithmeticMean(numbers: Double...) -&gt; Double {
var total: Double = 0
@ -793,14 +800,14 @@ arithmeticMean(1, 2, 3, 4, 5)
arithmeticMean(3, 8, 19)
// returns 10.0, which is the arithmetic mean of these three numbers
</code></pre><blockquote>
<p>注意:
一个函数至多能有一个可变参数,而且它必须是参数表中最后的一个。这样做是为了避免函数调用时出现歧义。</p>
<p>注意:</p>
<p>一个函数至多能有一个可变参数,而且它必须是参数表中最后的一个。这样做是为了避免函数调用时出现歧义。</p>
</blockquote>
<p>如果函数有一个或多个带默认值的参数,而且还有一个可变参数,那么把可变参数放在参数表的最后。</p>
<h3 id="-constant-and-variable-parameters-">常量参数和变量参数Constant and Variable Parameters</h3>
<p>函数参数默认是常量。试图在函数体中更改参数值将会导致编译错误。这意味着你不能错误地更改参数值。</p>
<p>但是,有时候,如果函数中有传入参数的变量值副本将是很有用的。你可以通过指定一个或多个参数为变量参数,从而避免自己在函数中定义新的变量。变量参数不是常量,你可以在函数中把它当做新的可修改副本来使用。</p>
<p>通过在参数名前加关键字<code>var</code>来定义变量参数:</p>
<p>通过在参数名前加关键字 <code>var</code> 来定义变量参数:</p>
<pre><code>func alignRight(var string: String, count: Int, pad: Character) -&gt; String {
let amountToPad = count - countElements(string)
for _ in 1...amountToPad {
@ -812,40 +819,41 @@ let originalString = &quot;hello&quot;
let paddedString = alignRight(originalString, 10, &quot;-&quot;)
// paddedString is equal to &quot;-----hello&quot;
// originalString is still equal to &quot;hello&quot;
</code></pre><p>这个例子中定义了一个新的叫做<code>alignRight</code>的函数,用来右对齐输入的字符串到一个长的输出字符串中。左侧空余的地方用指定的填充字符填充。这个例子中,字符串<code>&quot;hello&quot;</code>被转换成了<code>&quot;-----hello&quot;</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>
</code></pre><p>这个例子中定义了一个新的叫做 <code>alignRight</code> 的函数,用来右对齐输入的字符串到一个长的输出字符串中。左侧空余的地方用指定的填充字符填充。这个例子中,字符串<code>&quot;hello&quot;</code>被转换成了<code>&quot;-----hello&quot;</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>
<p>注意:
对变量参数所进行的修改在函数调用结束后变消息了,并且对于函数体外是不可见的。变量参数仅仅存在于函数调用的生命周期中。</p>
<p>注意:</p>
<p>对变量参数所进行的修改在函数调用结束后变消息了,并且对于函数体外是不可见的。变量参数仅仅存在于函数调用的生命周期中。</p>
</blockquote>
<h3 id="-in-out-parameters-">输入输出参数In-Out Parameters</h3>
<p>变量参数正如上面所述仅仅能在函数体内被更改。如果你想要一个函数可以修改参数的值并且想要在这些修改在函数调用结束后仍然存在那么就应该把这个参数定义为输入输出参数In-Out Parameters</p>
<p>定义一个输入输出参数时,在参数定义前加<code>inout</code>关键字。一个输入输出参数有传入函数的值,这个值被函数修改,然后被传出函数,替换原来的值。</p>
<p>定义一个输入输出参数时,在参数定义前加 <code>inout</code> 关键字。一个输入输出参数有传入函数的值,这个值被函数修改,然后被传出函数,替换原来的值。</p>
<p>你只能传入一个变量作为输入输出参数。你不能传入常量或者字面量literal value因为这些量是不能被修改的。当传入的参数作为输入输出参数时需要在参数前加<code>&amp;</code>符,表示这个值可以被函数修改。</p>
<blockquote>
<p>注意:
输入输出参数不能有默认值,而且变量参数不能用<code>inout</code>标记。如果你用<code>inout</code>标记一个参数,这个参数不能别<code>var</code>或者<code>let</code>标记。</p>
<p>注意:</p>
<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>
<p>下面是例子,<code>swapTwoInts</code> 函数,有两个分别叫做 <code>a</code><code>b</code> 的输出输出参数:</p>
<pre><code>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>
<p>你可以用两个<code>Int</code>型的变量来调用<code>swapTwoInts</code>。需要注意的是,<code>someInt</code><code>anotherInt</code>在传入<code>swapTwoInts</code>函数前,都加了<code>&amp;</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>&amp;</code> 的前缀:</p>
<pre><code>var someInt = 3
var anotherInt = 107
swapTwoInts(&amp;someInt, &amp;anotherInt)
println(&quot;someInt is now \(someInt), and anotherInt is now \(anotherInt)&quot;)
// prints &quot;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>注意:
输出输出参数和返回值是不一样的。上面的<code>swapTwoInts</code>函数并没有定义任何返回值,但仍然修改了<code>someInt</code><code>anotherInt</code>的值。输入输出参数是函数对函数体外产生影响的另一种方式。</p>
</blockquote>
<p>注意:</p>
<p>输出输出参数和返回值是不一样的。上面的 <code>swapTwoInts</code> 函数并没有定义任何返回值,但仍然修改了 <code>someInt</code><code>anotherInt</code> 的值。输入输出参数是函数对函数体外产生影响的另一种方式。
<a name="Function_Types"></a></p>
<h2 id="-function-types-">函数类型Function Types</h2>
</blockquote>
<p>每个函数都有种特定的函数类型,由函数的参数类型和返回类型组成。</p>
<p>例如:</p>
<pre><code>func addTwoInts(a: Int, b: Int) -&gt; Int {
@ -854,27 +862,27 @@ println(&quot;someInt is now \(someInt), and anotherInt is now \(anotherInt)&quo
func multiplyTwoInts(a: Int, b: Int) -&gt; Int {
return a * b
}
</code></pre><p>这个例子中定义了两个简单的数学函数:<code>addTwoInts</code><code>multiplyTwoInts</code>。这两个函数都传入两个<code>Int</code>类型, 返回一个合适的<code>Int</code>值。</p>
<p>这两个函数的类型是<code>(Int, Int) -&gt; Int</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) -&gt; Int</code>,可以读作“这个函数类型,它有两个 <code>Int</code> 型的参数并返回一个 <code>Int</code> 型的值。”。</p>
<p>下面是另一个例子,一个没有参数,也没有返回值的函数:</p>
<pre><code>func printHelloWorld() {
println(&quot;hello, world&quot;)
}
</code></pre><p>这个函数的类型是:<code>() -&gt; ()</code>,或者叫“没有参数,并返回<code>Void</code>类型的函数。”。没有指定返回类型的函数总返回 <code>Void</code>。在Swift中<code>Void</code>与空的元组是一样的。</p>
</code></pre><p>这个函数的类型是:<code>() -&gt; ()</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) -&gt; 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>
<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(&quot;Result: \(mathFunction(2, 3))&quot;)
// prints &quot;Result: 5
</code></pre><p>有相同匹配类型的不同函数可以被赋值给同一个变量,就像非函数类型的变量一样:</p>
<pre><code>mathFunction = multiplyTwoInts
println(&quot;Result: \(mathFunction(2, 3))&quot;)
// prints &quot;Result: 6&quot;
</code></pre><p>就像其他类型一样当赋值一个函数给常量或变量时你可以让Swift来推测其函数类型</p>
</code></pre><p>就像其他类型一样,当赋值一个函数给常量或变量时,你可以让 Swift 来推测其函数类型:</p>
<pre><code>let anotherMathFunction = addTwoInts
// anotherMathFunction is inferred to be of type (Int, Int) -&gt; Int
</code></pre><h3 id="-function-types-as-parameter-types-">函数类型作为参数类型Function Types as Parameter Types</h3>
@ -885,28 +893,28 @@ println(&quot;Result: \(mathFunction(2, 3))&quot;)
}
printMathResult(addTwoInts, 3, 5)
// prints &quot;Result: 8”
</code></pre><p>这个例子定义了<code>printMathResult</code>函数,它有三个参数:第一个参数叫<code>mathFunction</code>,类型是<code>(Int, Int) -&gt; 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>
</code></pre><p>这个例子定义了 <code>printMathResult</code> 函数,它有三个参数:第一个参数叫 <code>mathFunction</code>,类型是<code>(Int, Int) -&gt; 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>-&gt;</code>)后写一个完整的函数类型。</p>
<p>下面的这个例子中定义了两个简单函数,分别是<code>stepForward</code><code>stepBackward</code><code>stepForward</code>函数返回一个比输入值大一的值。<code>stepBackward</code>函数返回一个比输入值小一的值。这两个函数的类型都是<code>(Int) -&gt; Int</code></p>
<p>下面的这个例子中定义了两个简单函数,分别是 <code>stepForward</code> <code>stepBackward</code><code>stepForward</code> 函数返回一个比输入值大一的值。<code>stepBackward</code> 函数返回一个比输入值小一的值。这两个函数的类型都是 <code>(Int) -&gt; Int</code></p>
<pre><code>func stepForward(input: Int) -&gt; Int {
return input + 1
}
func stepBackward(input: Int) -&gt; Int {
return input - 1
}
</code></pre><p>下面这个叫做<code>chooseStepFunction</code>的函数,它的返回类型是<code>(Int) -&gt; Int</code>的函数。<code>chooseStepFunction</code>根据布尔值<code>backwards</code>来返回<code>stepForward</code>函数或<code>stepBackward</code>函数:</p>
</code></pre><p>下面这个叫做 <code>chooseStepFunction</code> 的函数,它的返回类型是 <code>(Int) -&gt; Int</code> 的函数。<code>chooseStepFunction</code> 根据布尔值 <code>backwards</code> 来返回 <code>stepForward</code> 函数或 <code>stepBackward</code> 函数:</p>
<pre><code>func chooseStepFunction(backwards: Bool) -&gt; (Int) -&gt; Int {
return backwards ? stepBackward : stepForward
}
</code></pre><p>你现在可以用<code>chooseStepFunction</code>来获得一个函数,不管是那个方向:</p>
</code></pre><p>你现在可以用 <code>chooseStepFunction</code> 来获得一个函数,不管是那个方向:</p>
<pre><code>var currentValue = 3
let moveNearerToZero = chooseStepFunction(currentValue &gt; 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 &gt; 0</code>是真的(<code>true</code>),这将使得<code>chooseStepFunction</code>返回<code>stepBackward</code>函数。一个指向返回的函数的引用保存在了<code>moveNearerToZero</code>常量中。</p>
<p>现在,<code>moveNearerToZero</code>指向了正确的函数,它可以被用来数到<code>0</code></p>
</code></pre><p>上面这个例子中计算出从 <code>currentValue</code> 逐渐接近到<code>0</code>是需要向正数走还是向负数走。<code>currentValue</code> 的初始值是<code>3</code>,这意味着 <code>currentValue &gt; 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(&quot;Counting to zero:&quot;)
// Counting to zero:
while currentValue != 0 {
@ -918,10 +926,11 @@ println(&quot;zero!&quot;)
// 2...
// 1...
// zero!
</code></pre><h2 id="-nested-functions-">嵌套函数Nested Functions</h2>
</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>
<p>你可以用返回嵌套函数的方式重写 <code>chooseStepFunction</code> 函数:</p>
<pre><code>func chooseStepFunction(backwards: Bool) -&gt; (Int) -&gt; Int {
func stepForward(input: Int) -&gt; Int { return input + 1 }
func stepBackward(input: Int) -&gt; Int { return input - 1 }
@ -985,6 +994,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>