swift學習筆記5 函數

注:英文部分來自官方文檔

Every function in Swift has a type, consisting of the function’s parameter types and return type. You can use this type like any other type in Swift, which makes it easy to pass functions as parameters to other functions, and to return functions from functions. Functions can also be written within other functions to encapsulate useful functionality within a nested function scope.

在swift中,每個函數都有一個類型,由函數的參數類型和返回類型構成。你可以像使用swift中的其他類型一樣使用該函數的類型,這使得把函數當作參數傳給另一個函數或從一個函數返回另一個函數變得很容易。函數也可以寫在其他函數體內,用以在一個嵌套的函數範圍內封裝有用的功能。

The function in the example below is called greet(person:), because that’s what it does—it takes a person’s name as input and returns a greeting for that person. To accomplish this, you define one input parameter—a String value called person—and a return type of String, which will contain a greeting for that person:

下面的函數是greet(person:),它把一個人的名字作爲輸入並返回一個對此人的問候。爲此,你需要定義一個輸入參數:一個string值,稱爲:person,返回一個string值,包含對此人的問候:

func greet(person: String) -> String {
    let greeting = "Hello, " + person + "!"
    return greeting
}

用右箭頭->表明返回類型,後面跟着返回類型的名稱。

  • 擁有多個返回值的函數

    You can use a tuple type as the return type for a function to return multiple values as part of one compound return value.


你可以用一個tuple類型作爲一個返回多個值的函數的返回類型。
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)
}

The minMax(array:) function returns a tuple containing two Int values. These values are labeled min and max so that they can be accessed by name when querying the function’s return value.

minMax(array:)函數返回了一個包含兩個int值的tuple。這兩個int值被標記爲min 和max,當要查詢函數返回值的時候可以通過名字來獲取。

Because the tuple’s member values are named as part of the function’s return type, they can be accessed with dot syntax to retrieve the minimum and maximum found values:

可以使用點語法來獲取最小值和最大值:
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"
  • 可選的tuple返回類型

If the tuple type to be returned from a function has the potential to have “no value” for the entire tuple, you can use an optional tuple return type to reflect the fact that the entire tuple can be nil. You write an optional tuple return type by placing a question mark after the tuple type’s closing parenthesis, such as (Int, Int)? or (String, Int, Bool)?.

如果從函數返回的tuple類型有可能是沒值的,那麼你可以用可選的tuple返回類型。寫法是在tuple的括號後邊加上問號,比如: (Int, Int)?或(String, Int, Bool)?

An optional tuple type such as (Int, Int)? is different from a tuple that contains optional types such as (Int?, Int?). With an optional tuple type, the entire tuple is optional, not just each individual value within the tuple.

一個可選的tuple類型–比如(Int, Int)?–跟一個包含可選類型的tuple–比如 (Int?, Int?)–是不一樣的。可選的tuple類型指的是整個tuple是可選的(optional),而不是值它內部包含的值是可選的。

The minMax(array:) function above returns a tuple containing two Int values. However, the function does not perform any safety checks on the array it is passed. If the array argument contains an empty array, the minMax(array:) function, as defined above, will trigger a runtime error when attempting to access array[0].

上面的minMax(array:) 函數返回一個包含兩個int值的tuple。但是該函數並沒有對傳入的數組作安全檢查,如果這個數組參數是一個空數組,那麼minMax(array:)函數在獲取array[0]時就會報一個runtime錯誤。

To handle an empty array safely, write the minMax(array:) function with an optional tuple return type and return a value of nil when the array is empty:

爲了安全地處理空數組,把minMax(array:)的返回類型寫爲可選的tuple,當數組爲空時返回nil:

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)
}

函數參數標記和參數名

Each function parameter has both an argument label and a parameter name. The argument label is used when calling the function; each argument is written in the function call with its argument label before it. The parameter name is used in the implementation of the function. By default, parameters use their parameter name as their argument label.

函數的每個參數都有參數標記和參數名。 參數標記是調用函數時使用的,每個參數在函數調用時前面都有參數標記。參數名是在函數實現裏使用的。參數使用它們的參數名作爲默認的參數標記。

    func someFunction(firstParameterName: Int, secondParameterName:  Int) {
        // 在函數體內, firstParameterName and secondParameterName
        // 指向第一第二個參數的值
    }
    someFunction(firstParameterName: 1, secondParameterName: 2)

All parameters must have unique names. Although it’s possible for multiple parameters to have the same argument label, unique argument labels help make your code more readable.

所有的參數都應該有一個獨一無二的名字。即使多個參數可以有相同的參數標記,但是獨一無二的參數標記使得你的代碼更易讀。
指定參數標記
參數標記寫在參數名之前,用空格隔開

    func someFunction(argumentLabel parameterName: Int) {
        // 函數體內, parameterName 指向該參數的值

    }

Here’s a variation of the greet(person:) function that takes a person’s name and hometown and returns a greeting:

下面是一個 greet(person:) 函數的變體(使用了參數標記):取person的名字和家鄉爲輸入,返回一個greeting:

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."

The use of argument labels can allow a function to be called in an expressive, sentence-like manner, while still providing a function body that is readable and clear in intent.

使用參數標記可以使得一個函數被表達式調用時更像一個句子,同時在函數內部可讀性更好更清晰。
省略參數標記

If you don’t want an argument label for a parameter, write an underscore (_) instead of an explicit argument label for that parameter.

如果你不想使用參數標記,用下劃線_ 取代該參數的參數標記。

    func someFunction(_ firstParameterName:Int , secondParameterName:  Int ) {
        // 在函數體內, firstParameterName and secondParameterName
        // 指向第一第二個參數的值
    }
    someFunction(1, secondParameterName: 2)

in-out 參數

Function parameters are constants by default. Trying to change the value of a function parameter from within the body of that function results in a compile-time error. This means that you can’t change the value of a parameter by mistake. If you want a function to modify a parameter’s value, and you want those changes to persist after the function call has ended, define that parameter as an in-out parameter instead.

函數參數默認都是常量。 如果在函數內部改變一個參數的值會導致編譯時錯誤。
這意味着你不能錯誤地修改參數值。如果你想在函數內修改參數的值,並且在函數調用完之後保持這種修改,那麼你需要把參數定義爲in-out參數。

You write an in-out parameter by placing the inout keyword right before a parameter’s type. An in-out parameter has a value that is passed in to the function, is modified by the function, and is passed back out of the function to replace the original value.

in-out參數需要在參數類型前加上inout 關鍵字。in-out參數是這樣一種參數:被傳入函數,在函數內被修改,然後再被函數返回替代掉其原始的值。

You can only pass a variable as the argument for an in-out parameter. You cannot pass a constant or a literal value as the argument, because constants and literals cannot be modified. You place an ampersand (&) directly before a variable’s name when you pass it as an argument to an in-out parameter, to indicate that it can be modified by the function.

只能把變量傳作in-out參數。不能把常量字面量傳作in-out參數,因爲常量字面量不可修改。
當你把變量傳作in-out參數時,在其變量名之前加上&符號,表明其可被函數修改。

In-out parameters cannot have default values, and variadic parameters cannot be marked as inout.

in-out參數不能有默認值,可變參數不能標記爲inout

一個例子:

    func swapTwoInts(_ a: inout   Int, _ b: inout   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"

從上面的例子中可以看到,someInt 和anotherInt的初始值被函數swapTwoInts修改了。

函數類型

Every function has a specific function type, made up of the parameter types and the return type of the function.

每個函數都有一個特定的函數類型,由參數類型和返回類型組成

    func addTwoInts(_ a:  a href="" Int /a , _ b:  a href="" Int /a ) ->  a href="" Int /a  {
        return a + b
    }
    func multiplyTwoInts(_ a:  a href="" Int /a , _ b:  a href="" Int /a ) ->  a href="" Int /a  {
        return a * b
    }
    The type of both of these functions is (Int, Int) -> Int. This can be read as:
    “A function that has two parameters, both of type Int, and that returns a value of type Int.”

這兩個函數的類型都是(Int, Int) -> Int。這可以這麼讀:
一個接收兩個類型都爲int讀參數並返回一個int類型的值的函數。

在一個例子;

    func printHelloWorld() {
        print("hello, world")
    }
    The type of this function is () -> Void, or “a function that has no parameters, and returns Void.”

該函數的類型是() -> Void,讀作:一個沒有參數,返回void的函數

使用函數類型

You use function types just like any other types in Swift. For example, you can define a constant or variable to be of a function type and assign an appropriate function to that variable:

在swift中,你可以像使用其他類型一樣使用函數類型。
比如,你可以定義一個變量或常量爲函數類型,並把對應的函數賦給那個變量。
var mathFunction: ( Int, Int) -> Int = addTwoInts

You can now call the assigned function with the name mathFunction:

現在你可以用名字mathFunction來調用該函數:

    print("Result: \(mathFunction(2, 3))")
    // Prints "Result: 5"

A different function with the same matching type can be assigned to the same variable, in the same way as for non-function types:

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

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

函數類型作爲參數類型

You can use a function type such as (Int, Int) -> Int as a parameter type for another function. This enables you to leave some aspects of a function’s implementation for the function’s caller to provide when the function is called.

你可以把一個函數類型—比如這樣的(Int, Int) -> Int— 作爲另一個函數的參數類型。
這使得你可以把一個函數的部分實現放到函數的調用者裏去。
一個例子:

    func printMathResult(_ mathFunction: ( a href="" Int /a ,  a href="" Int /a ) ->  a href="" Int /a , _ a:  a href="" Int /a , _ b:  a href="" Int /a ) {
        print("Result: \(mathFunction(a, b))")
    }
    printMathResult(addTwoInts, 3, 5)
    // Prints "Result: 8"

This example defines a function called printMathResult(::_:), which has three parameters. The first parameter is called mathFunction, and is of type (Int, Int) -> Int. You can pass any function of that type as the argument for this first parameter. The second and third parameters are called a and b, and are both of type Int. These are used as the two input values for the provided math function.

這個例子定義了一個函數printMathResult(::_:),此函數有三個參數。第一個參數是mathFunction,類型是(Int, Int) -> Int。你可以給第一個參數傳任意此類型的函數。第二第三個參數是a和b,都是int類型。他們用作mathFunction函數的輸入。

When printMathResult(:::) is called, it is passed the addTwoInts(:_:) function, and the integer values 3 and 5. It calls the provided function with the values 3 and 5, and prints the result of 8.

調用printMathResult(:::)時,傳入了addTwoInts(::)函數,整數3和整數5。它調用了addTwoInts(:_:)函數,並把3和5作爲輸入值,最後結果打印8.

函數類型作爲返回類型

You can use a function type as the return type of another function. You do this by writing a complete function type immediately after the return arrow (->) of the returning function.

你可以把一個函數類型作爲另一個函數的返回類型。
只需要把完整的函數類型寫在返回箭頭後邊。

The next example defines two simple functions called stepForward(:) and stepBackward(:). The stepForward(:) function returns a value one more than its input value, and the stepBackward(:) function returns a value one less than its input value. Both functions have a type of (Int) -> Int:

下面的兩個例子定義了兩個簡單的函數stepForward(:) 和 stepBackward(:)。
stepForward(:)函數返回一個比它的輸入值大1的值,stepBackward(:)函數返回一個比它大輸入值小1的值。
兩個函數都有一個類型(Int) -> Int :

    func stepForward(_ input:  a href="" Int /a ) ->  a href="" Int /a  {
        return input + 1
    }
    func stepBackward(_ input:  a href="" Int /a ) ->  a href="" Int /a  {
        return input - 1
    }

    Here’s a function called chooseStepFunction(backward:), whose return type is (Int) -> Int. The chooseStepFunction(backward:) function returns the stepForward(_:) function or the stepBackward(_:) function based on a Boolean parameter called backward:

再有一個函數chooseStepFunction(backward:),它的返回類型是(Int) -> Int。 chooseStepFunction(backward:)函數基於一個布爾參數—名字叫backward—的值來決定是返回stepForward(:)函數還是返回stepBackward(:) 函數

    func chooseStepFunction(backward:  a href="" Bool /a ) -> ( a href="" Int /a ) ->  a href="" Int /a  {
        return backward ? stepBackward : stepForward
    }

嵌套函數

All of the functions you have encountered so far in this chapter have been examples of global functions, which are defined at a global scope. You can also define functions inside the bodies of other functions, known as nested functions.

目前你在例子中看到的函數都是全局函數,定義爲全局範圍。你可以在其他函數內部定義函數,稱爲嵌套函數。

Nested functions are hidden from the outside world by default, but can still be called and used by their enclosing function. An enclosing function can also return one of its nested functions to allow the nested function to be used in another scope.

嵌套函數默認對外部隱藏,但依然可以被包圍(enclosing)它的函數調用和使用。包圍函數同樣可以把它的嵌套函數返回,使該嵌套函數在其他範圍內得以使用。

改寫上面的chooseStepFunction(backward:)函數,使用和返回嵌套函數

    func chooseStepFunction(backward:  a href="" Bool /a ) -> ( a href="" Int /a ) ->  a href="" Int /a  {
        func stepForward(input:  a href="" Int /a ) ->  a href="" Int /a  { return input + 1 }
        func stepBackward(input:  a href="" Int /a ) ->  a href="" Int /a  { 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!
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章