Swift學習筆記 (十五) 函數(下)

忽略參數標籤

如果你不希望爲某個參數添加一個標籤,可以使⽤一個下劃線( _ )來代替⼀個明確的參數標籤。

func someFunction(_ firstParameterName: Int, secondParameterName: Int) {

// 在函數體內,firstParameterName 和 secondParameterName 代表參數中的第一個和第二個參數值

}

someFunction(1, secondParameterName: 2)

如果⼀個參數有一個標籤,那麼在調用的時候必須使用標籤來標記這個參數。

 

默認參數值

你可以在函數體中通過給參數賦值來爲任意一個參數定義默認值(Deafult Value)。當默認值被定義後,調⽤這個函數時可以忽略

這個參數。

func someFunction(parameterWithoutDefault: Int, parameterWithDefault: Int = 12) {

            // 如果你在調用時候不傳第二個參數,parameterWithDefault 會值爲 12 傳入到函數體中。

}

someFunction(parameterWithoutDefault: 3, parameterWithDefault: 6)               // parameterWithDefault = 6

someFunction(parameterWithoutDefault: 4)                                                           // parameterWithDefault = 12

將不帶有默認值的參數放在函數參數列表的最前面。一般來說,沒有默認值的參數更加的重要,將不帶默認值的參數放在最前面

保證在函數調用時,非默認參數的順序是一致的,同時也使得相同的函數在不同情況下調用時顯得更爲清晰。

 

可變參數

一個可變參數(variadic parameter)可以接受零個或多個值。函數調用時,你可以用可變參數來指定函數參數可以被傳入不確定

數量的輸入值。通過在變量類型名後面加入( ... )的方式來定義可變參數。

可變參數的傳入值在函數體中變爲此類型的一個數組。例如,一個叫做 numbers 的 Double... 型可變參數,在函數體內可以當

做一個叫 numbers 的 [Double] 型的數組常量。

下面的這個函數用來計算一組任意長度數字的算術平均數(arithmetic mean):

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)

// 返回 3.0, 是這 5 個數的平均數。

arithmeticMean(3, 8.25, 18.75)

// 返回 10.0, 是這 3 個數的平均數。

注意

一個函數最多隻能擁有⼀個可變參數。

 

輸入輸出參數

函數參數默認是常量。試圖在函數體中更改參數值將會導致編譯錯誤。這意味着你不能錯誤地更改參數值。如果你想要一個函數

可以修改參數的值,並且想要這些修改在函數調用結束後仍然存在,那麼就應該把這個參數定義爲輸入輸出參數 (In-Out

Parameters)。

定義一個輸入輸出參數時,在參數定義前加 inout 關鍵字。一個輸入輸出參數有傳入函數的值,這個值被函數修改,然後被傳出

函數,替換原來的值。想獲取更多的關於輸入輸出參數的細節和相關的編譯器優化,請查看《輸⼊入輸出參數》一 節。

你只能傳遞變量給輸入輸出參數。你不能傳入常量或者字⾯量,因爲這些值是不能被修改的。當傳入的參數作爲輸入輸出參數

時,需要在參數名前加 & 符,表示這個值可以被函數修改。

注意

輸入輸出參數不能有默認值,而且可變參數不能用 inout 標記。

下例中, swapTwoInts(_:_:) 函數有兩個分別叫做 a 和 b 的輸入輸出參數:

func swapTwoInts(_ a: inout Int, _ b: inout Int) {

       let temporaryA = a

       a=b

       b = temporaryA

}

swapTwoInts(_:_:) 函數簡單地交換 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)")

// 打印“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 值。

這兩個函數的類型是 (Int, Int) -> Int ,可以解讀爲: “這個函數類型有兩個 Int 型的參數並返回一個 Int 型的值”。 下⾯是另一個例

子,一個沒有參數,也沒有返回值的函數:

func printHelloWorld() {

        print("hello, world")

}

這個函數的類型是: () -> Void ,或者叫“沒有參數,並返回值爲 Void 類型的函數”。

 

使用函數類型

在 Swift 中,使用函數類型就像使用其他類型一樣。例如,你可以定義一個類型爲函數的常量或變量,並將適當的函數賦值給它:

var mathFunction: (Int, Int) -> Int = addTwoInts

這段代碼可以被解讀爲:

”定義一個叫做 mathFunction 的變量,類型是‘一個有兩個 Int 型的參數並返回一個 Int 型的值的函數’,並讓這個新變量指向 

addTwoInts 函數”。

addTwoInts 和 mathFunction 有同樣的類型,所以這個賦值過程在 Swift 類型檢查(type-check)中是允許的。 現在,你可以用 

mathFunction 來調用被賦值的函數了:

print("Result: \(mathFunction(2, 3))")

// Prints "Result: 5"

有相同匹配類型的不同函數可以被賦值給同一個變量,就像非函數類型的變量一樣:

mathFunction = multiplyTwoInts

print("Result: \(mathFunction(2, 3))")

// Prints "Result: 6"

就像其他類型一樣,當賦值一個函數給常量或變量時,你可以讓 Swift 來推斷其函數類型:

let anotherMathFunction = addTwoInts

// anotherMathFunction 被推斷爲 (Int, Int) -> Int 類型

 

函數類型作爲參數類型

你可以⽤ (Int, Int) -> Int 這樣的函數類型作爲另一個函數的參數類型。這樣你可以將函數的一部分實現留給函數的調用者來提

供。

下⾯是另一個例子,正如上面的函數一樣,同樣是輸出某種數學運算結果:

func printMathResult(_ mathFunction: (Int, Int) -> Int, _ a: Int, _ b: Int) {

       print("Result: \(mathFunction(a, b))")

}

printMathResult(addTwoInts, 3, 5)// 打印“Result: 8”

這個例子定義了 printMathResult(_:_:_:) 函數,它有三個參數:第⼀個參數叫 mathFunction ,類型是 (Int, Int) -> Int ,你可以傳⼊

任何這種類型的函數;第二個和第三個參數叫 a 和 b ,它們的類型都是 Int ,這兩個值作爲已給出的函數的輸⼊值。

當 printMathResult(_:_:_:) 被調用時,它被傳入 addTwoInts 函數和整數 3 和 5 。它用傳入 3 和 5 調用 addTwoInts ,並輸出結果: 

8 。

printMathResult(_:_:_:) 函數的作用就是輸出另一個適當類型的數學函數的調⽤結果。它不關心傳入函數是如何實現的,只關心傳

⼊的函數是不是一個正確的類型。這使得 printMathResult(_:_:_:) 能以一種類型安全(type- safe)的方式將一部分功能轉給調用者

實現。

 

函數類型作爲返回類型

你可以用函數類型作爲另一個函數的返回類型。你需要做的是在返回箭頭(->)後寫一個完整的函數類型。

下⾯的這個例子中定義了兩個簡單函數,分別是 stepForward(_:) 和 stepBackward(_:) 。 stepForward(_:)函數返回一個比輸入值

⼤ 1 的值。 stepBackward(_:) 函數返回一個比輸入值小 1 的值。這兩個函數的類型都是(Int) -> Int :

func stepForward(_ input: Int) -> Int {

          return input + 1

}


func stepBackward(_ input: Int) -> Int {

        return input - 1

}

如下名爲 chooseStepFunction(backward:) 的函數,它的返回類型是 (Int) -> Int 類型的函數。 chooseStepFunction(backward:) 

根據布爾值 backwards 來返回 stepForward(_:) 函數或 stepBackward(_:) 函數:

func chooseStepFunction(backward: Bool) -> (Int) -> Int {

        return backward ? stepBackward : stepForward

}

你現在可以用 chooseStepFunction(backward:) 來獲得兩個函數其中的一個:

var currentValue = 3

let moveNearerToZero = chooseStepFunction(backward: currentValue > 0)

// moveNearerToZero 現在指向 stepBackward() 函數。

上⾯這個例子中計算出從 currentValue 逐漸接近到0是需要向正數走還是向負數走。 currentValue 的初始值是3 ,這意味着 

currentValue > 0 爲真(true),這將使得 chooseStepFunction(_:) 返回stepBackward(_:) 函數。一個指向返回的函數的引⽤保存在

了 moveNearerToZero 常量中。

現在, moveNearerToZero 指向了正確的函數,它可以被用來數到零:

print("Counting to zero:")

// Counting to zero:

while currentValue != 0 {

         print("\(currentValue)... ")

         currentValue = moveNearerToZero(currentValue)
}

print("zero!")

// 3...

// 2...

// 1...

// zero!

 

嵌套函數

到目前爲止本章中你所見到的所有函數都叫全局函數(global functions),它們定義在全局域中。你也可以把函數定義在別的函數

體中,稱作嵌套函數(nested functions)。

默認情況下,嵌套函數是對外界不可見的,但是可以被它們的外圍函數(enclosing function)調用。一個外圍函數也可以返回它

的某一個嵌套函數,使得這個函數可以在其他域中被使用。

你可以用返回嵌套函數的方式重寫 chooseStepFunction(backward:) 函數:

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!

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章