函數(shù)是用來完成特定任務的獨立的代碼塊。你給一個函數(shù)起一個合適的名字,用來標識函數(shù)做什么,并且當函數(shù)需要執(zhí)行的時候,這個名字會被“調用”。
Swift 統(tǒng)一的函數(shù)語法足夠靈活,可以用來表示任何函數(shù),包括從最簡單的沒有參數(shù)名字的 C 風格函數(shù),到復雜的帶局部和外部參數(shù)名的 Objective-C 風格函數(shù)。參數(shù)可以提供默認值,以簡化函數(shù)調用。參數(shù)也可以既當做傳入?yún)?shù),也當做傳出參數(shù),也就是說,一旦函數(shù)執(zhí)行結束,傳入的參數(shù)值可以被修改。
在 Swift 中,每個函數(shù)都有一種類型,包括函數(shù)的參數(shù)值類型和返回值類型。你可以把函數(shù)類型當做任何其他普通變量類型一樣處理,這樣就可以更簡單地把函數(shù)當做別的函數(shù)的參數(shù),也可以從其他函數(shù)中返回函數(shù)。函數(shù)的定義可以寫在在其他函數(shù)定義中,這樣可以在嵌套函數(shù)范圍內實現(xiàn)功能封裝。
當你定義一個函數(shù)時,你可以定義一個或多個有名字和類型的值,作為函數(shù)的輸入(稱為參數(shù),parameters),也可以定義某種類型的值作為函數(shù)執(zhí)行結束的輸出(稱為返回類型)。
每個函數(shù)有個函數(shù)名,用來描述函數(shù)執(zhí)行的任務。要使用一個函數(shù)時,你用函數(shù)名“調用”,并傳給它匹配的輸入值(稱作實參,arguments)。一個函數(shù)的實參必須與函數(shù)參數(shù)表里參數(shù)的順序一致。
在下面例子中的函數(shù)叫做"greetingForPerson"
,之所以叫這個名字是因為這個函數(shù)用一個人的名字當做輸入,并返回給這個人的問候語。為了完成這個任務,你定義一個輸入?yún)?shù)-一個叫做 personName
的 String
值,和一個包含給這個人問候語的 String
類型的返回值:
func sayHello(personName: String) -> String {
let greeting = "Hello, " + personName + "!"
return greeting
}
所有的這些信息匯總起來成為函數(shù)的定義,并以 func
作為前綴。指定函數(shù)返回類型時,用返回箭頭 ->
(一個連字符后跟一個右尖括號)后跟返回類型的名稱的方式來表示。
該定義描述了函數(shù)做什么,它期望接收什么和執(zhí)行結束時它返回的結果是什么。這樣的定義使的函數(shù)可以在別的地方以一種清晰的方式被調用:
println(sayHello("Anna"))
// prints "Hello, Anna!"
println(sayHello("Brian"))
// prints "Hello, Brian!"
調用 sayHello
函數(shù)時,在圓括號中傳給它一個 String
類型的實參。因為這個函數(shù)返回一個 String
類型的值,sayHello
可以被包含在 println
的調用中,用來輸出這個函數(shù)的返回值,正如上面所示。
在 sayHello
的函數(shù)體中,先定義了一個新的名為 greeting
的 String
常量,同時賦值了給 personName
的一個簡單問候消息。然后用 return
關鍵字把這個問候返回出去。一旦 return greeting
被調用,該函數(shù)結束它的執(zhí)行并返回 greeting
的當前值。
你可以用不同的輸入值多次調用 sayHello
。上面的例子展示的是用"Anna"
和"Brian"
調用的結果,該函數(shù)分別返回了不同的結果。
為了簡化這個函數(shù)的定義,可以將問候消息的創(chuàng)建和返回寫成一句:
func sayHelloAgain(personName: String) -> String {
return "Hello again, " + personName + "!"
}
println(sayHelloAgain("Anna"))
// prints "Hello again, Anna!"
函數(shù)參數(shù)與返回值在Swift中極為靈活。你可以定義任何類型的函數(shù),包括從只帶一個未名參數(shù)的簡單函數(shù)到復雜的帶有表達性參數(shù)名和不同參數(shù)選項的復雜函數(shù)。
函數(shù)可以有多個輸入?yún)?shù),寫在圓括號中,用逗號分隔。
下面這個函數(shù)用一個半開區(qū)間的開始點和結束點,計算出這個范圍內包含多少數(shù)字:
func halfOpenRangeLength(start: Int, end: Int) -> Int {
return end - start
}
println(halfOpenRangeLength(1, 10))
// prints "9"
函數(shù)可以沒有參數(shù)。下面這個函數(shù)就是一個無參函數(shù),當被調用時,它返回固定的 String
消息:
func sayHelloWorld() -> String {
return "hello, world"
}
println(sayHelloWorld())
// prints "hello, world"
盡管這個函數(shù)沒有參數(shù),但是定義中在函數(shù)名后還是需要一對圓括號。當被調用時,也需要在函數(shù)名后寫一對圓括號。
函數(shù)可以沒有返回值。下面是 sayHello
函數(shù)的另一個版本,叫 waveGoodbye
,這個函數(shù)直接輸出 String
值,而不是返回它:
func sayGoodbye(personName: String) {
println("Goodbye, \(personName)!")
}
sayGoodbye("Dave")
// prints "Goodbye, Dave!"
因為這個函數(shù)不需要返回值,所以這個函數(shù)的定義中沒有返回箭頭(->)和返回類型。
注意: 嚴格上來說,雖然沒有返回值被定義,
sayGoodbye
函數(shù)依然返回了值。沒有定義返回類型的函數(shù)會返回特殊的值,叫Void
。它其實是一個空的元組(tuple),沒有任何元素,可以寫成()
。
被調用時,一個函數(shù)的返回值可以被忽略:
func printAndCount(stringToPrint: String) -> Int {
println(stringToPrint)
return countElements(stringToPrint)
}
func printWithoutCounting(stringToPrint: String) {
printAndCount(stringToPrint)
}
printAndCount("hello, world")
// prints "hello, world" and returns a value of 12
printWithoutCounting("hello, world")
// prints "hello, world" but does not return a value
第一個函數(shù) printAndCount
,輸出一個字符串并返回 Int
類型的字符數(shù)。第二個函數(shù) printWithoutCounting
調用了第一個函數(shù),但是忽略了它的返回值。當?shù)诙€函數(shù)被調用時,消息依然會由第一個函數(shù)輸出,但是返回值不會被用到。
注意: 返回值可以被忽略,但定義了有返回值的函數(shù)必須返回一個值,如果在函數(shù)定義底部沒有返回任何值,這將導致編譯錯誤(compile-time error)。
你可以用元組(tuple)類型讓多個值作為一個復合值從函數(shù)中返回。
下面的這個例子中,count
函數(shù)用來計算一個字符串中元音,輔音和其他字母的個數(shù)(基于美式英語的標準)。
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 {
case "a", "e", "i", "o", "u":
++vowels
case "b", "c", "d", "f", "g", "h", "j", "k", "l", "m",
"n", "p", "q", "r", "s", "t", "v", "w", "x", "y", "z":
++consonants
default:
++others
}
}
return (vowels, consonants, others)
}
你可以用 count
函數(shù)來處理任何一個字符串,返回的值將是一個包含三個 Int
型值的元組(tuple):
let total = count("some arbitrary string!")
println("\(total.vowels) vowels and \(total.consonants) consonants")
// prints "6 vowels and 13 consonants"
需要注意的是,元組的成員不需要在函數(shù)中返回時命名,因為它們的名字已經(jīng)在函數(shù)返回類型中有了定義。
以上所有的函數(shù)都給它們的參數(shù)定義了參數(shù)名(parameter name)
:
func someFunction(parameterName: Int) {
// function body goes here, and can use parameterName
// to refer to the argument value for that parameter
}
但是,這些參數(shù)名僅在函數(shù)體中使用,不能在函數(shù)調用時使用。這種類型的參數(shù)名被稱作局部參數(shù)名(local parameter name)
,因為它們只能在函數(shù)體中使用。
有時候,調用函數(shù)時,給每個參數(shù)命名是非常有用的,因為這些參數(shù)名可以指出各個實參的用途是什么。
如果你希望函數(shù)的使用者在調用函數(shù)時提供參數(shù)名字,那就需要給每個參數(shù)除了局部參數(shù)名外再定義一個外部參數(shù)名
。外部參數(shù)名寫在局部參數(shù)名之前,用空格分隔。
func someFunction(externalParameterName localParameterName: Int) {
// function body goes here, and can use localParameterName
// to refer to the argument value for that parameter
}
注意: 如果你提供了外部參數(shù)名,那么函數(shù)在被調用時,必須使用外部參數(shù)名。
以下是個例子,這個函數(shù)使用一個結合者(joiner)
把兩個字符串聯(lián)在一起:
func join(s1: String, s2: String, joiner: String) -> String {
return s1 + joiner + s2
}
當你調用這個函數(shù)時,這三個字符串的用途是不清楚的:
join("hello", "world", ", ")
// returns "hello, world"
為了讓這些字符串的用途更為明顯,我們?yōu)?join
函數(shù)添加外部參數(shù)名:
func join(string s1: String, toString s2: String, withJoiner joiner: String) -> String {
return s1 + joiner + s2
}
在這個版本的 join
函數(shù)中,第一個參數(shù)有一個叫 string
的外部參數(shù)名和 s1
的局部參數(shù)名,第二個參數(shù)有一個叫 toString
的外部參數(shù)名和 s2
的局部參數(shù)名,第三個參數(shù)有一個叫 withJoiner
的外部參數(shù)名和 joiner
的局部參數(shù)名。
現(xiàn)在,你可以使用這些外部參數(shù)名以一種清晰地方式來調用函數(shù)了:
join(string: "hello", toString: "world", withJoiner: ", ")
// returns "hello, world"
使用外部參數(shù)名讓第二個版本的 join
函數(shù)的調用更為有表現(xiàn)力,更為通順,同時還保持了函數(shù)體是可讀的和有明確意圖的。
注意: 當其他人在第一次讀你的代碼,函數(shù)參數(shù)的意圖顯得不明顯時,考慮使用外部參數(shù)名。如果函數(shù)參數(shù)名的意圖是很明顯的,那就不需要定義外部參數(shù)名了。
如果你需要提供外部參數(shù)名,但是局部參數(shù)名已經(jīng)定義好了,那么你不需要寫兩次參數(shù)名。相反,只寫一次參數(shù)名,并用井號(#)
作為前綴就可以了。這告訴 Swift 使用這個參數(shù)名作為局部和外部參數(shù)名。
下面這個例子定義了一個叫 containsCharacter
的函數(shù),使用井號(#)
的方式定義了外部參數(shù)名:
func containsCharacter(#string: String, #characterToFind: Character) -> Bool {
for character in string {
if character == characterToFind {
return true
}
}
return false
}
這樣定義參數(shù)名,使得函數(shù)體更為可讀,清晰,同時也可以以一個不含糊的方式被調用:
let containsAVee = containsCharacter(string: "aardvark", characterToFind: "v")
// containsAVee equals true, because "aardvark" contains a "v”
你可以在函數(shù)體中為每個參數(shù)定義默認值
。當默認值被定義后,調用這個函數(shù)時可以忽略這個參數(shù)。
注意: 將帶有默認值的參數(shù)放在函數(shù)參數(shù)列表的最后。這樣可以保證在函數(shù)調用時,非默認參數(shù)的順序是一致的,同時使得相同的函數(shù)在不同情況下調用時顯得更為清晰。
以下是另一個版本的join
函數(shù),其中joiner
有了默認參數(shù)值:
func join(string s1: String, toString s2: String, withJoiner joiner: String = " ") -> String {
return s1 + joiner + s2
}
像第一個版本的 join
函數(shù)一樣,如果 joiner
被賦值時,函數(shù)將使用這個字符串值來連接兩個字符串:
join(string: "hello", toString: "world", withJoiner: "-")
// returns "hello-world"
當這個函數(shù)被調用時,如果 joiner
的值沒有被指定,函數(shù)會使用默認值(" "):
join(string: "hello", toString:"world")
// returns "hello world"
在大多數(shù)情況下,給帶默認值的參數(shù)起一個外部參數(shù)名是很有用的。這樣可以保證當函數(shù)被調用且?guī)J值的參數(shù)被提供值時,實參的意圖是明顯的。
為了使定義外部參數(shù)名更加簡單,當你未給帶默認值的參數(shù)提供外部參數(shù)名時,Swift 會自動提供外部名字。此時外部參數(shù)名與局部名字是一樣的,就像你已經(jīng)在局部參數(shù)名前寫了井號(#)
一樣。
下面是 join
函數(shù)的另一個版本,這個版本中并沒有為它的參數(shù)提供外部參數(shù)名,但是 joiner
參數(shù)依然有外部參數(shù)名:
func join(s1: String, s2: String, joiner: String = " ") -> String {
return s1 + joiner + s2
}
在這個例子中,Swift 自動為 joiner
提供了外部參數(shù)名。因此,當函數(shù)調用時,外部參數(shù)名必須使用,這樣使得參數(shù)的用途變得清晰。
join("hello", "world", joiner: "-")
// returns "hello-world"
注意: 你可以使用
下劃線(_)
作為默認值參數(shù)的外部參數(shù)名,這樣可以在調用時不用提供外部參數(shù)名。但是給帶默認值的參數(shù)命名總是更加合適的。
一個可變參數(shù)(variadic parameter)
可以接受一個或多個值。函數(shù)調用時,你可以用可變參數(shù)來傳入不確定數(shù)量的輸入?yún)?shù)。通過在變量類型名后面加入(...)
的方式來定義可變參數(shù)。
傳入可變參數(shù)的值在函數(shù)體內當做這個類型的一個數(shù)組。例如,一個叫做 numbers
的 Double...
型可變參數(shù),在函數(shù)體內可以當做一個叫 numbers
的 Double[]
型的數(shù)組常量。
下面的這個函數(shù)用來計算一組任意長度數(shù)字的算術平均數(shù):
func arithmeticMean(numbers: Double...) -> Double {
var total: Double = 0
for number in numbers {
total += number
}
return total / Double(numbers.count)
}
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
注意: 一個函數(shù)至多能有一個可變參數(shù),而且它必須是參數(shù)表中最后的一個。這樣做是為了避免函數(shù)調用時出現(xiàn)歧義。
如果函數(shù)有一個或多個帶默認值的參數(shù),而且還有一個可變參數(shù),那么把可變參數(shù)放在參數(shù)表的最后。
函數(shù)參數(shù)默認是常量。試圖在函數(shù)體中更改參數(shù)值將會導致編譯錯誤。這意味著你不能錯誤地更改參數(shù)值。
但是,有時候,如果函數(shù)中有傳入?yún)?shù)的變量值副本將是很有用的。你可以通過指定一個或多個參數(shù)為變量參數(shù),從而避免自己在函數(shù)中定義新的變量。變量參數(shù)不是常量,你可以在函數(shù)中把它當做新的可修改副本來使用。
通過在參數(shù)名前加關鍵字 var
來定義變量參數(shù):
func alignRight(var string: String, count: Int, pad: Character) -> String {
let amountToPad = count - countElements(string)
if amountToPad < 1 {
return string
}
let padString = String(pad)
for _ in 1...amountToPad {
string = padString + string
}
return string
}
let originalString = "hello"
let paddedString = alignRight(originalString, 10, "-")
// paddedString is equal to "-----hello"
// originalString is still equal to "hello"
這個例子中定義了一個新的叫做 alignRight
的函數(shù),用來右對齊輸入的字符串到一個長的輸出字符串中。左側空余的地方用指定的填充字符填充。這個例子中,字符串"hello"
被轉換成了"-----hello"
。
alignRight
函數(shù)將參數(shù) string
定義為變量參數(shù)。這意味著 string
現(xiàn)在可以作為一個局部變量,用傳入的字符串值初始化,并且可以在函數(shù)體中進行操作。
該函數(shù)首先計算出多少個字符需要被添加到 string
的左邊,以右對齊到總的字符串中。這個值存在局部常量 amountToPad
中。這個函數(shù)然后將 amountToPad
多的填充(pad)字符填充到 string
左邊,并返回結果。它使用了 string
這個變量參數(shù)來進行所有字符串操作。
注意: 對變量參數(shù)所進行的修改在函數(shù)調用結束后便消失了,并且對于函數(shù)體外是不可見的。變量參數(shù)僅僅存在于函數(shù)調用的生命周期中。
變量參數(shù),正如上面所述,僅僅能在函數(shù)體內被更改。如果你想要一個函數(shù)可以修改參數(shù)的值,并且想要在這些修改在函數(shù)調用結束后仍然存在,那么就應該把這個參數(shù)定義為輸入輸出參數(shù)(In-Out Parameters)。
定義一個輸入輸出參數(shù)時,在參數(shù)定義前加 inout
關鍵字。一個輸入輸出參數(shù)有傳入函數(shù)的值,這個值被函數(shù)修改,然后被傳出函數(shù),替換原來的值。
你只能將變量作為輸入輸出參數(shù)。你不能傳入常量或者字面量(literal value),因為這些量是不能被修改的。當傳入的參數(shù)作為輸入輸出參數(shù)時,需要在參數(shù)前加&
符,表示這個值可以被函數(shù)修改。
注意: 輸入輸出參數(shù)不能有默認值,而且可變參數(shù)不能用
inout
標記。如果你用inout
標記一個參數(shù),這個參數(shù)不能被var
或者let
標記。
下面是例子,swapTwoInts
函數(shù),有兩個分別叫做 a
和 b
的輸入輸出參數(shù):
func swapTwoInts(inout a: Int, inout b: Int) {
let temporaryA = a
a = b
b = temporaryA
}
這個 swapTwoInts
函數(shù)僅僅交換 a
與 b
的值。該函數(shù)先將 a
的值存到一個暫時常量 temporaryA
中,然后將 b
的值賦給 a
,最后將 temporaryA
幅值給 b
。
你可以用兩個 Int
型的變量來調用 swapTwoInts
。需要注意的是,someInt
和 anotherInt
在傳入 swapTwoInts
函數(shù)前,都加了 &
的前綴:
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”
從上面這個例子中,我們可以看到 someInt
和 anotherInt
的原始值在 swapTwoInts
函數(shù)中被修改,盡管它們的定義在函數(shù)體外。
注意: 輸入輸出參數(shù)和返回值是不一樣的。上面的
swapTwoInts
函數(shù)并沒有定義任何返回值,但仍然修改了someInt
和anotherInt
的值。輸入輸出參數(shù)是函數(shù)對函數(shù)體外產(chǎn)生影響的另一種方式。
每個函數(shù)都有種特定的函數(shù)類型,由函數(shù)的參數(shù)類型和返回類型組成。
例如:
func addTwoInts(a: Int, b: Int) -> Int {
return a + b
}
func multiplyTwoInts(a: Int, b: Int) -> Int {
return a * b
}
這個例子中定義了兩個簡單的數(shù)學函數(shù):addTwoInts
和 multiplyTwoInts
。這兩個函數(shù)都傳入兩個 Int
類型, 返回一個合適的Int
值。
這兩個函數(shù)的類型是 (Int, Int) -> Int
,可以讀作“這個函數(shù)類型,它有兩個 Int
型的參數(shù)并返回一個 Int
型的值。”。
下面是另一個例子,一個沒有參數(shù),也沒有返回值的函數(shù):
func printHelloWorld() {
println("hello, world")
}
這個函數(shù)的類型是:() -> ()
,或者叫“沒有參數(shù),并返回 Void
類型的函數(shù)”。沒有指定返回類型的函數(shù)總返回 Void
。在Swift中,Void
與空的元組是一樣的。
在 Swift 中,使用函數(shù)類型就像使用其他類型一樣。例如,你可以定義一個類型為函數(shù)的常量或變量,并將函數(shù)賦值給它:
var mathFunction: (Int, Int) -> Int = addTwoInts
這個可以讀作:
“定義一個叫做 mathFunction
的變量,類型是‘一個有兩個 Int
型的參數(shù)并返回一個 Int
型的值的函數(shù)’,并讓這個新變量指向 addTwoInts
函數(shù)”。
addTwoInts
和 mathFunction
有同樣的類型,所以這個賦值過程在 Swift 類型檢查中是允許的。
現(xiàn)在,你可以用 mathFunction
來調用被賦值的函數(shù)了:
println("Result: \(mathFunction(2, 3))")
// prints "Result: 5"
有相同匹配類型的不同函數(shù)可以被賦值給同一個變量,就像非函數(shù)類型的變量一樣:
mathFunction = multiplyTwoInts
println("Result: \(mathFunction(2, 3))")
// prints "Result: 6"
就像其他類型一樣,當賦值一個函數(shù)給常量或變量時,你可以讓 Swift 來推斷其函數(shù)類型:
let anotherMathFunction = addTwoInts
// anotherMathFunction is inferred to be of type (Int, Int) -> Int
你可以用(Int, Int) -> Int
這樣的函數(shù)類型作為另一個函數(shù)的參數(shù)類型。這樣你可以將函數(shù)的一部分實現(xiàn)交由給函數(shù)的調用者。
下面是另一個例子,正如上面的函數(shù)一樣,同樣是輸出某種數(shù)學運算結果:
func printMathResult(mathFunction: (Int, Int) -> Int, a: Int, b: Int) {
println("Result: \(mathFunction(a, b))")
}
printMathResult(addTwoInts, 3, 5)
// prints "Result: 8”
這個例子定義了 printMathResult
函數(shù),它有三個參數(shù):第一個參數(shù)叫 mathFunction
,類型是(Int, Int) -> Int
,你可以傳入任何這種類型的函數(shù);第二個和第三個參數(shù)叫 a
和 b
,它們的類型都是 Int
,這兩個值作為已給的函數(shù)的輸入值。
當 printMathResult
被調用時,它被傳入 addTwoInts
函數(shù)和整數(shù)3
和5
。它用傳入3
和5
調用 addTwoInts
,并輸出結果:8
。
printMathResult
函數(shù)的作用就是輸出另一個合適類型的數(shù)學函數(shù)的調用結果。它不關心傳入函數(shù)是如何實現(xiàn)的,它只關心這個傳入的函數(shù)類型是正確的。這使得 printMathResult
可以以一種類型安全(type-safe)的方式來保證傳入函數(shù)的調用是正確的。
你可以用函數(shù)類型作為另一個函數(shù)的返回類型。你需要做的是在返回箭頭(->
)后寫一個完整的函數(shù)類型。
下面的這個例子中定義了兩個簡單函數(shù),分別是 stepForward
和stepBackward
。stepForward
函數(shù)返回一個比輸入值大一的值。stepBackward
函數(shù)返回一個比輸入值小一的值。這兩個函數(shù)的類型都是 (Int) -> Int
:
func stepForward(input: Int) -> Int {
return input + 1
}
func stepBackward(input: Int) -> Int {
return input - 1
}
下面這個叫做 chooseStepFunction
的函數(shù),它的返回類型是 (Int) -> Int
的函數(shù)。chooseStepFunction
根據(jù)布爾值 backwards
來返回 stepForward
函數(shù)或 stepBackward
函數(shù):
func chooseStepFunction(backwards: Bool) -> (Int) -> Int {
return backwards ? stepBackward : stepForward
}
你現(xiàn)在可以用 chooseStepFunction
來獲得一個函數(shù),不管是那個方向:
var currentValue = 3
let moveNearerToZero = chooseStepFunction(currentValue > 0)
// moveNearerToZero now refers to the stepBackward() function
上面這個例子中計算出從 currentValue
逐漸接近到0
是需要向正數(shù)走還是向負數(shù)走。currentValue
的初始值是3
,這意味著 currentValue > 0
是真的(true
),這將使得 chooseStepFunction
返回 stepBackward
函數(shù)。一個指向返回的函數(shù)的引用保存在了 moveNearerToZero
常量中。
現(xiàn)在,moveNearerToZero
指向了正確的函數(shù),它可以被用來數(shù)到0
:
println("Counting to zero:")
// Counting to zero:
while currentValue != 0 {
println("\(currentValue)... ")
currentValue = moveNearerToZero(currentValue)
}
println("zero!")
// 3...
// 2...
// 1...
// zero!
這章中你所見到的所有函數(shù)都叫全局函數(shù)(global functions),它們定義在全局域中。你也可以把函數(shù)定義在別的函數(shù)體中,稱作嵌套函數(shù)(nested functions)。
默認情況下,嵌套函數(shù)是對外界不可見的,但是可以被他們封閉函數(shù)(enclosing function)來調用。一個封閉函數(shù)也可以返回它的某一個嵌套函數(shù),使得這個函數(shù)可以在其他域中被使用。
你可以用返回嵌套函數(shù)的方式重寫 chooseStepFunction
函數(shù):
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
}
var currentValue = -4
let moveNearerToZero = chooseStepFunction(currentValue < 0)
// moveNearerToZero now refers to the nested stepForward() function
while currentValue != 0 {
println("\(currentValue)... ")
currentValue = moveNearerToZero(currentValue)
}
println("zero!")
// -4...
// -3...
// -2...
// -1...
// zero!
更多建議: