指南:函式(Functions)

weixin_33785972發表於2016-06-06

函式的定義與呼叫(Defining and Calling Functions)

  • 以func作為字首
  • 指定函式返回型別時,用返回箭頭 ->(一個連字元後跟一個右尖括號)後跟返回型別的名稱的方式來表示
func sayHello(personName: String) -> String {
    let greeting = "Hello, " + personName + "!"
    return greeting
}
print(sayHello("Anna"))
// prints "Hello, Anna!"
print(sayHello("Brian"))
// prints "Hello, Brian!"

函式引數與返回值(Function Parameters and Return Values)

  • 函式如果不需要返回值,函式的定義中可以沒有返回箭頭(->)和返回型別
func sayGoodbye(personName: String) {
    print("Goodbye, \(personName)!")
}
sayGoodbye("Dave")
// prints "Goodbye, Dave!"
  • 可以用元組(tuple)型別讓多個值作為一個複合值從函式中返回
  • 如果函式返回的元組型別有可能整個元組都“沒有值”,你可以使用可選的(Optional) 元組返回型別反映整個元組可以是nil的事實。你可以通過在元組型別的右括號後放置一個問號來定義一個可選元組,例如(Int, Int)?或(String, Int, Bool)?
  • 可選元組型別如(Int, Int)?與元組包含可選型別如(Int?, Int?)是不同的.可選的元組型別,整個元組是可選的,而不只是元組中的每個元素值。
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)
}

if let bounds = minMax([8, -6, 2, 109, 3, 71]) {
    print("min is \(bounds.min) and max is \(bounds.max)")
}
// prints "min is -6 and max is 109"

函式引數名稱(Function Parameter Names)

  • 函式引數都有一個外部引數名(external parameter name)和一個區域性引數名(local parameter name)。外部引數名用於在函式呼叫時標註傳遞給函式的引數,區域性引數名在函式的實現內部使用。
  • 可以在區域性引數名前指定外部引數名,中間以空格分隔;如果提供了外部引數名,那麼函式在被呼叫時,必須使用外部引數名。
  • 使用外部函式名可以使函式以一種更富有表達性的類似句子的方式呼叫,並使函式體意圖清晰,更具可讀性。
  • 一般情況下,第一個引數省略其外部引數名,第二個以及隨後的引數使用其區域性引數名作為外部引數名。
  • 如果不想為第二個及後續的引數設定外部引數名,用一個下劃線(_)代替一個明確的引數名。因為第一個引數預設忽略其外部引數名稱,顯式地寫下劃線是多餘的。
func sayHello(to person: String, and anotherPerson: String) -> String {
    return "Hello \(person) and \(anotherPerson)!"
}
print(sayHello(to: "Bill", and: "Ted"))
// prints "Hello Bill and Ted!"

func sayHello(person: String, anotherPerson: String) -> String {
    return "Hello \(person) and \(anotherPerson)!"
}
print(sayHello( "Bill", anotherPerson: "Ted"))
// prints "Hello Bill and Ted!"

func sayHello(person: String, _ anotherPerson: String) -> String {
    return "Hello \(person) and \(anotherPerson)!"
}
print(sayHello("Bill",  "Ted"))
// prints "Hello Bill and Ted!"
  • 你可以在函式體中為每個引數定義預設值(Deafult Values)。當預設值被定義後,呼叫這個函式時可以忽略這個引數。
  • 將帶有預設值的引數放在函式引數列表的最後。這樣可以保證在函式呼叫時,非預設引數的順序是一致的,同時使得相同的函式在不同情況下呼叫時顯得更為清晰。
func someFunction(parameterWithDefault: Int = 12) {
    // function body goes here
    // if no arguments are passed to the function call,
    // value of parameterWithDefault is 12
}
someFunction(6) // parameterWithDefault is 6
someFunction() // parameterWithDefault is 12
  • 一個可變引數(variadic parameter)可以接受零個或多個值。函式呼叫時,你可以用可變引數來指定函式引數可以被傳入不確定數量的輸入值。通過在變數型別名後面加入(...)的方式來定義可變引數。
  • 可變引數的傳入值在函式體中變為此型別的一個陣列。
  • 一個函式最多隻能有一個可變引數。
  • 如果函式有一個或多個帶預設值的引數,而且還有一個可變引數,那麼把可變引數放在參數列的最後。
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 Parameters)。
  • 定義一個輸入輸出引數時,在引數定義前加 inout 關鍵字。
  • 當傳入的引數作為輸入輸出引數時,需要在引數名前加&符,表示這個值可以被函式修改。
  • 只能傳遞變數給輸入輸出引數。不能傳入常量或者字面量(literal value),因為這些量是不能被修改的。
  • 輸入輸出引數不能有預設值,不能是可變引數。
func swapTwoInts(inout a: Int, inout _ b: Int) {
    let temporaryA = a
    a = b
    b = temporaryA
}
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"

函式型別(Function Types)

  • 每個函式都有種特定的函式型別,由函式的引數型別和返回型別組成。
  • 在 Swift 中,使用函式型別就像使用其他型別一樣。可以定義一個型別為函式的常量或變數,並將適當的函式賦值給它
  • 函式型別可以作為另一個函式的引數型別。這樣可以將函式的一部分實現留給函式的呼叫者來提供。
func addTwoInts(a: Int, _ b: Int) -> Int {
    return a + b
}
func multiplyTwoInts(a: Int, _ b: Int) -> Int {
    return a * b
}

var mathFunction: (Int, Int) -> Int = addTwoInts
print("Result: \(mathFunction(2, 3))")
// prints "Result: 5"

mathFunction = multiplyTwoInts
print("Result: \(mathFunction(2, 3))")
// prints "Result: 6"

func printMathResult(mathFunction: (Int, Int) -> Int, _ a: Int, _ b: Int) {
    print("Result: \(mathFunction(a, b))")
}
printMathResult(addTwoInts, 3, 5)
// prints "Result: 8"
printMathResult(multiplyTwoInts, 3, 5)
// prints "Result: 15"
  • 可以用函式型別作為另一個函式的返回型別。在返回箭頭(->)後寫一個完整的函式型別。
func stepForward(input: Int) -> Int {
    return input + 1
}
func stepBackward(input: Int) -> Int {
    return input - 1
}
func chooseStepFunction(backwards: Bool) -> (Int) -> Int {
    return backwards ? stepBackward : stepForward
}
var currentValue = 3
let moveNearerToZero = chooseStepFunction(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!

函式作為引數,作為返回值,是函數語言程式設計的基礎

巢狀函式(Nested Functions)

  • 全域性函式(global functions):定義在全域性域中。
  • 巢狀函式(nested functions):定義在別的函式體中。
  • 預設情況下,巢狀函式是對外界不可見的,但是可以被它們的外圍函式(enclosing function)呼叫。
  • 一個外圍函式也可以返回它的某一個巢狀函式,使得這個函式可以在其他域中被使用。
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 {
    print("\(currentValue)... ")
    currentValue = moveNearerToZero(currentValue)
}
print("zero!")
// -4...
// -3...
// -2...
// -1...
// zero!

相關文章