位置:首頁 > 高級語言 > Swift教學 > Swift函數參數名稱

Swift函數參數名稱

函數參數名稱(Function Parameter Names)

以上所有的函數都給它們的參數定義了參數名(parameter name)

func someFunction(parameterName: Int) {
    // function body goes here, and can use parameterName
    // to refer to the argument value for that parameter
}

但是,這些參數名僅在函數體中使用,不能在函數調用時使用。這種類型的參數名被稱作局部參數名(local parameter name),因為它們隻能在函數體中使用。

外部參數名(External Parameter Names)

有時候,調用函數時,給每個參數命名是非常有用的,因為這些參數名可以指出各個實參的用途是什麼。

如果你希望函數的使用者在調用函數時提供參數名字,那就需要給每個參數除了局部參數名外再定義一個外部參數名。外部參數名寫在局部參數名之前,用空格分隔。

func someFunction(externalParameterName localParameterName: Int) {
    // function body goes here, and can use localParameterName
    // to refer to the argument value for that parameter
}


注意:
如果你提供了外部參數名,那麼函數在被調用時,必須使用外部參數名。
 

以下是個例子,這個函數使用一個結合者(joiner)把兩個字符串聯在一起:

func join(s1: String, s2: String, joiner: String) -> String {
    return s1 + joiner + s2
}

當你調用這個函數時,這三個字符串的用途是不清楚的:

join("hello", "world", ", ")
// returns "hello, world"

為了讓這些字符串的用途更為明顯,我們為 join 函數添加外部參數名:

func join(string s1: String, toString s2: String, withJoiner joiner: String) -> String {
    return s1 + joiner + s2
}

在這個版本的 join 函數中,第一個參數有一個叫 string 的外部參數名和 s1 的局部參數名,第二個參數有一個叫toString 的外部參數名和 s2 的局部參數名,第三個參數有一個叫 withJoiner 的外部參數名和 joiner 的局部參數名。

現在,你可以使用這些外部參數名以一種清晰地方式來調用函數了:

join(string: "hello", toString: "world", withJoiner: ", ")
// returns "hello, world"

使用外部參數名讓第二個版本的 join 函數的調用更為有表現力,更為通順,同時還保持了函數體是可讀的和有明確意圖的。


注意:
當其他人在第一次讀你的代碼,函數參數的意圖顯得不明顯時,考慮使用外部參數名。如果函數參數名的意圖是很明顯的,那就不需要定義外部參數名了。
 

簡寫外部參數名(Shorthand External Parameter Names)

如果你需要提供外部參數名,但是局部參數名已經定義好了,那麼你不需要寫兩次這些參數名。相反,隻寫一次參數名,並用井號(#)作為前綴就可以了。這告訴 Swift 使用這個參數名作為局部和外部參數名。

下麵這個例子定義了一個叫 containsCharacter 的函數,使用井號(#)的方式定義了外部參數名:

func containsCharacter(#string: String, #characterToFind: Character) -> Bool {
    for character in string {
        if character == characterToFind {
            return true
        }
    }
    return false
}

這樣定義參數名,使得函數體更為可讀,清晰,同時也可以以一個不含糊的方式被調用:

let containsAVee = containsCharacter(string: "aardvark", characterToFind: "v")
// containsAVee equals true, because "aardvark" contains a "v”

默認參數值(Default Parameter Values)

你可以在函數體中為每個參數定義默認值。當默認值被定義後,調用這個函數時可以略去這個參數。


注意:
將帶有默認值的參數放在函數參數表的最後。這樣可以保證在函數調用時,非默認參數的順序是一致的,同時使得相同的函數在不同情況下調用時顯得更為清晰。
 

以下是另一個版本的join函數,其中joiner有了默認參數值:

func join(string s1: String, toString s2: String, withJoiner joiner: String = " ") -> String {
    return s1 + joiner + s2
}

像第一個版本的 join 函數一樣,如果 joiner 被賦值時,函數將使用這個字符串值來連接兩個字符串:

join(string: "hello", toString: "world", withJoiner: "-")
// returns "hello-world"

當這個函數被調用時,如果 joiner 的值冇有被指定,函數會使用默認值(" "):

join(string: "hello", toString:"world")
// returns "hello world"

默認值參數的外部參數名(External Names for Parameters with Default Values)

在大多數情況下,給帶默認值的參數起一個外部參數名是很有用的。這樣可以保證當函數被調用且帶默認值的參數被提供值時,實參的意圖是明顯的。

為了使定義外部參數名更加簡單,當你未給帶默認值的參數提供外部參數名時,Swift 會自動提供外部名字。此時外部參數名與局部名字是一樣的,就像你已經在局部參數名前寫了井號(#)一樣。

下麵是 join 函數的另一個版本,這個版本中並冇有為它的參數提供外部參數名,但是 joiner 參數依然有外部參數名:

func join(s1: String, s2: String, joiner: String = " ") -> String {
    return s1 + joiner + s2
}

在這個例子中,Swift 自動為 joiner 提供了外部參數名。因此,當函數調用時,外部參數名必須使用,這樣使得參數的用途變得清晰。

join("hello", "world", joiner: "-")
// returns "hello-world"


注意:
你可以使用下劃線(_)作為默認值參數的外部參數名,這樣可以在調用時不用提供外部參數名。但是給帶默認值的參數命名總是更加合適的。
 

可變參數(Variadic Parameters)

一個可變參數(variadic parameter)可以接受一個或多個值。函數調用時,你可以用可變參數來傳入不確定數量的輸入參數。通過在變量類型名後麵加入(...)的方式來定義可變參數。

傳入可變參數的值在函數體內當做這個類型的一個數組。例如,一個叫做 numbers 的 Double... 型可變參數,在函數體內可以當做一個叫 numbers 的 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, 19)
// returns 10.0, which is the arithmetic mean of these three numbers


注意:
一個函數至多能有一個可變參數,而且它必須是參數表中最後的一個。這樣做是為了避免函數調用時出現歧義。
 

如果函數有一個或多個帶默認值的參數,而且還有一個可變參數,那麼把可變參數放在參數表的最後。

常量參數和變量參數(Constant and Variable Parameters)

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

但是,有時候,如果函數中有傳入參數的變量值副本將是很有用的。你可以通過指定一個或多個參數為變量參數,從而避免自己在函數中定義新的變量。變量參數不是常量,你可以在函數中把它當做新的可修改副本來使用。

通過在參數名前加關鍵字 var 來定義變量參數:

func alignRight(var string: String, count: Int, pad: Character) -> String {
    let amountToPad = count - countElements(string)
    for _ in 1...amountToPad {
        string = pad + string
    }
    return string
}
let originalString = "hello"
let paddedString = alignRight(originalString, 10, "-")
// paddedString is equal to "-----hello"
// originalString is still equal to "hello"

這個例子中定義了一個新的叫做 alignRight 的函數,用來右對齊輸入的字符串到一個長的輸出字符串中。左側空餘的地方用指定的填充字符填充。這個例子中,字符串"hello"被轉換成了"-----hello"

alignRight 函數將參數 string 定義為變量參數。這意味著 string 現在可以作為一個局部變量,用傳入的字符串值初始化,並且可以在函數體中進行操作。

該函數首先計算出多少個字符需要被添加到 string 的左邊,以右對齊到總的字符串中。這個值存在局部常量amountToPad 中。這個函數然後將 amountToPad 多的填充(pad)字符填充到 string 左邊,並返回結果。它使用了string 這個變量參數來進行所有字符串操作。


注意:
對變量參數所進行的修改在函數調用結束後便消失了,並且對於函數體外是不可見的。變量參數僅僅存在於函數調用的生命周期中。
 

輸入輸出參數(In-Out Parameters)

變量參數,正如上麵所述,僅僅能在函數體內被更改。如果你想要一個函數可以修改參數的值,並且想要在這些修改在函數調用結束後仍然存在,那麼就應該把這個參數定義為輸入輸出參數(In-Out Parameters)。

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

你隻能傳入一個變量作為輸入輸出參數。你不能傳入常量或者字麵量(literal value),因為這些量是不能被修改的。當傳入的參數作為輸入輸出參數時,需要在參數前加&符,表示這個值可以被函數修改。


注意:
輸入輸出參數不能有默認值,而且可變參數不能用 inout 標記。如果你用 inout 標記一個參數,這個參數不能被var 或者 let 標記。
 

下麵是例子,swapTwoInts 函數,有兩個分彆叫做 a 和 b 的輸出輸出參數:

func swapTwoInts(inout a: Int, inout b: 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)
println("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 的值。輸入輸出參數是函數對函數體外產生影響的另一種方式。