定義和調用函數
在下面的例子中的函數叫做greet(person :),因為這是它的作用 - 它需要一個人的名字作為輸入,并返回一個問候語的人。 為了實現這一點,你定義一個輸入參數 - 一個String值,稱為person - 和一個String的返回類型,它將包含該人的問候語:
func greet(person: String) -> String {
let greeting = "Hello, " + person + "!"
return greeting
}
所有這些信息都匯總到函數的定義中,前綴是func關鍵字。 通過返回箭頭 - >(一個連字符后跟一個直角括號)來指示函數的返回類型,后面跟著要返回的類型的名稱。
該定義描述了函數的作用,它期望接收的內容,以及它完成后返回的內容。 該定義使得函數可以從代碼中的其他位置輕松調用:
print(greet(person: "Anna"))
// Prints "Hello, Anna!"
print(greet(person: "Brian"))
// Prints "Hello, Brian!"
要使此函數的主體更短,可以將消息創建和return語句合并為一行:
func greetAgain(person: String) -> String {
return "Hello again, " + person + "!"
}
print(greetAgain(person: "Anna"))
// Prints "Hello again, Anna!"
函數參數和返回值
無參數的函數
func sayHelloWorld() -> String {
return "hello, world"
}
print(sayHelloWorld())
// Prints "hello, world"
多個參數的函數
func greet(person: String, alreadyGreeted: Bool) -> String {
if alreadyGreeted {
return greetAgain(person: person)
} else {
return greet(person: person)
}
}
print(greet(person: "Tim", alreadyGreeted: true))
// Prints "Hello again, Tim!"
無返回值的函數
func greet(person: String) {
print("Hello, \(person)!")
}
greet(person: "Dave")
// Prints "Hello, Dave!"
因為它不需要返回值,所以函數的定義不包括返回箭頭( - >)或返回類型。
注意:
嚴格地說,這個版本的greet(person :)函數仍然返回一個值,即使沒有定義返回值。 沒有定義的返回類型的函數返回類型為Void的特殊值。 這只是一個空的元組,它寫成()。
調用函數時,可以忽略函數的返回值:
func printAndCount(string: String) -> Int {
print(string)
return string.characters.count
}
func printWithoutCounting(string: String) {
let _ = printAndCount(string: string)
}
printAndCount(string: "hello, world")
// prints "hello, world" and returns a value of 12
printWithoutCounting(string: "hello, world")
// prints "hello, world" but does not return a value
第一個函數printAndCount(string :)打印一個字符串,然后將其字符計數作為Int返回。 第二個函數printWithoutCounting(string :)調用第一個函數,但忽略它的返回值。 當調用第二個函數時,消息仍由第一個函數打印,但不使用返回的值。
具有多個返回值的函數
func minMax(array: [Int]) -> (min: Int, max: Int) {
var currentMin = array[0]
var currentMax = array[0]
for value in array[1..<array.count] {
if value < currentMin {
currentMin = value
} else if value > currentMax {
currentMax = value
}
}
return (currentMin, currentMax)
}
因為元組的成員值被命名為函數的返回類型的一部分,所以可以使用點語法訪問它們以檢索最小和最大找到的值:
let bounds = minMax(array: [8, -6, 2, 109, 3, 71])
print("min is \(bounds.min) and max is \(bounds.max)")
// Prints "min is -6 and max is 109"
注意
元組的成員不需要在從函數返回元組的點處命名,因為它們的名稱已經被指定為函數的返回類型的一部分。
可選元組返回類型
func minMax(array: [Int]) -> (min: Int, max: Int)? {
if array.isEmpty { return nil }
var currentMin = array[0]
var currentMax = array[0]
for value in array[1..<array.count] {
if value < currentMin {
currentMin = value
} else if value > currentMax {
currentMax = value
}
}
return (currentMin, currentMax)
}
您可以使用可選綁定來檢查此版本的minMax(array :)函數是否返回實際的元組值或nil:
if let bounds = minMax(array: [8, -6, 2, 109, 3, 71]) {
print("min is \(bounds.min) and max is \(bounds.max)")
}
// Prints "min is -6 and max is 109"
函數參數標簽和參數名稱
每個函數參數都具有參數標簽和參數名稱。 參數標簽在調用函數時使用; 每個參數寫在函數調用中,其參數標簽在它之前。 參數名稱用于函數的實現。 默認情況下,參數使用其參數名稱作為其參數標簽。
func someFunction(firstParameterName: Int, secondParameterName: Int) {
// In the function body, firstParameterName and secondParameterName
// refer to the argument values for the first and second parameters.
}
someFunction(firstParameterName: 1, secondParameterName: 2)
所有參數必須具有唯一的名稱。 盡管多個參數可能具有相同的參數標簽,但唯一的參數標簽有助于使代碼更具可讀性。
指定參數標簽
您在參數名稱之前寫入參數標簽,用空格分隔:
func someFunction(argumentLabel parameterName: Int) {
// In the function body, parameterName refers to the argument value
// for that parameter.
}
這里有一個greet(person :)函數的變體,它使用一個人的姓名和家鄉并返回問候語:
func greet(person: String, from hometown: String) -> String {
return "Hello \(person)! Glad you could visit from \(hometown)."
}
print(greet(person: "Bill", from: "Cupertino"))
// Prints "Hello Bill! Glad you could visit from Cupertino."
省略參數標簽
如果不想要參數的參數標簽,請為該參數編寫下劃線(_),而不是顯式參數標簽。
func someFunction(_ firstParameterName: Int, secondParameterName: Int) {
// In the function body, firstParameterName and secondParameterName
// refer to the argument values for the first and second parameters.
}
someFunction(1, secondParameterName: 2)
注意:
如果參數具有參數標簽,則在調用函數時必須標記參數。
默認參數值
您可以通過為該參數的類型之后的參數分配值來為該函數中的任何參數定義默認值。 如果定義了默認值,則可以在調用該函數時忽略該參數。
func someFunction(parameterWithoutDefault: Int, parameterWithDefault: Int = 12) {
// If you omit the second argument when calling this function, then
// the value of parameterWithDefault is 12 inside the function body.
}
someFunction(parameterWithoutDefault: 3, parameterWithDefault: 6) // parameterWithDefault is 6
someFunction(parameterWithoutDefault: 4) // parameterWithDefault is 12
將沒有默認值的參數放在函數的參數列表的開頭,在具有默認值的參數之前。 沒有默認值的參數通常對函數的意義更重要。
變量參數
傳遞給可變參數的值在函數體內作為適當類型的數組使用。 例如,具有數字名稱和Double ...類型的可變參數在函數體內作為稱為[Double]類型的常數數組。下面的示例計算任何長度的數字列表的算術平均值(也稱為平均值):
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.25, 18.75)
// returns 10.0, which is the arithmetic mean of these three numbers
輸入 - 輸出參數
默認情況下,函數參數是常量。試圖從函數體內更改函數參數的值會導致編譯時錯誤。這意味著您不能錯誤地更改參數的值。如果希望函數修改參數的值,并且希望這些更改在函數調用結束后保留??,請將該參數定義為in-out參數。
您通過將inout參數放在參數類型之前來編寫in-out參數。輸入 - 輸出參數具有傳遞到函數的值,由函數修改,并被傳回函數以替換原始值。有關輸入參數和關聯編譯器優化行為的詳細討論,請參閱輸入參數。
您只能將一個變量作為in-out參數的參數傳遞。您不能將常量或字面值作為參數傳遞,因為常量和字面值不能修改。在將變量的名稱作為參數傳遞給in-out參數時,在變量名稱前放置一個&符號(&),以指示它可以由函數修改。
注意:
輸入 - 輸出參數不能具有默認值,并且可變參數不能標記為輸入。
下面是一個名為swapTwoInts(: :)的函數的示例,它有兩個in-out整數參數a和b:
func swapTwoInts(_ a: inout Int, _ b: inout Int) {
let temporaryA = a
a = b
b = temporaryA
}
swapTwoInts(: :)函數只是將b的值轉換為a,將a的值轉換為b。 該函數通過將a的值存儲在名為temporaryA的臨時常量中,將b的值分配給a,然后將temporaryA分配給b來執行此交換。
您可以調用具有兩個Int類型變量的swapTwoInts(: :)函數來交換它們的值。 請注意,someInt和anotherInt的名稱在傳遞給swapTwoInts(: :)函數時,以&符號作為前綴:
var someInt = 3
var anotherInt = 107
swapTwoInts(&someInt, &anotherInt)
print("someInt is now \(someInt), and anotherInt is now \(anotherInt)")
// Prints "someInt is now 107, and anotherInt is now 3"
上面的示例顯示,someInt和anotherInt的原始值由swapTwoInts(: :)函數修改,即使它們最初在函數之外定義。
輸入 - 輸出參數與函數返回值不同。 上面的swapTwoInts示例沒有定義返回類型或返回值,但它仍然修改someInt和anotherInt的值。 輸入 - 輸出參數是函數具有超出函數體范圍的效果的替代方法。
函數類型
每個函數都有一個特定的函數類型,由參數類型和函數的返回類型組成。
func addTwoInts(_ a: Int, _ b: Int) -> Int {
return a + b
}
func multiplyTwoInts(_ a: Int, _ b: Int) -> Int {
return a * b
}
此示例定義了兩個簡單的數學函數,稱為addTwoInts和multiplyTwoInts。 這些函數各取兩個Int值,并返回一個Int值。
你在Swift中使用類似任何其他類型的函數類型。 例如,您可以將常量或變量定義為函數類型,并為該變量分配適當的函數:
var mathFunction: (Int, Int) -> Int = addTwoInts
這可以看作:
“定義一個名為mathFunction的變量,它的類型是一個函數,它接受兩個Int值,并返回一個Int值。設置這個新變量以引用稱為addTwoInts的函數。
addTwoInts(: :)函數與mathFunction變量具有相同的類型,因此Swift的類型檢查器允許此賦值。現在可以調用名為mathFunction的已分配函數:
print("Result: \(mathFunction(2, 3))")
// Prints "Result: 5"
與任何其他類型一樣,當您將函數分配給常量或變量時,您可以將其留給Swift來推斷函數類型:
let anotherMathFunction = addTwoInts
// anotherMathFunction is inferred to be of type (Int, Int) -> Int
函數作為參數
func printMathResult(_ mathFunction: (Int, Int) -> Int, _ a: Int, _ b: Int) {
print("Result: \(mathFunction(a, b))")
}
printMathResult(addTwoInts, 3, 5)
// Prints "Result: 8"
函數作為返回值
func stepForward(_ input: Int) -> Int {
return input + 1
}
func stepBackward(_ input: Int) -> Int {
return input - 1
}
這里有一個名為chooseStepFunction(backward :)的函數,它的返回類型是(Int) - > Int。 chooseStepFunction(backward :)函數基于一個名為backward的布爾參數返回stepForward(_ :)函數或stepBackward(_ :)函數:
func chooseStepFunction(backward: Bool) -> (Int) -> Int {
return backward ? stepBackward : stepForward
}
你現在可以使用chooseStepFunction(backward :)來獲取一個方向或另一個方向的函數:
var currentValue = 3
let moveNearerToZero = chooseStepFunction(backward: currentValue > 0)
// moveNearerToZero now refers to the stepBackward() function
print("Counting to zero:")
// Counting to zero:
while currentValue != 0 {
print("\(currentValue)... ")
currentValue = moveNearerToZero(currentValue)
}
print("zero!")
// 3...
// 2...
// 1...
// zero!
嵌套函數
func chooseStepFunction(backward: Bool) -> (Int) -> Int {
func stepForward(input: Int) -> Int { return input + 1 }
func stepBackward(input: Int) -> Int { return input - 1 }
return backward ? stepBackward : stepForward
}
var currentValue = -4
let moveNearerToZero = chooseStepFunction(backward: currentValue > 0)
// moveNearerToZero now refers to the nested stepForward() function
while currentValue != 0 {
print("\(currentValue)... ")
currentValue = moveNearerToZero(currentValue)
}
print("zero!")
// -4...
// -3...
// -2...
// -1...
// zero!