讀古今文學網 > iOS編程基礎:Swift、Xcode和Cocoa入門指南 > 2.2 外部參數名 >

2.2 外部參數名

函數可以外化其參數名。外部名稱要作為實參的標籤出現在對函數的調用中。這麼做是有意義的,原因如下:

·闡明了每個實參的作用;每個實參名都能表示出自己對函數動作的作用。

·將函數區分開來;兩個函數可能有相同的名字和簽名,但卻擁有不同的外化參數名。

·有助於Swift與Objective-C和Cocoa的通信,後者的方法參數幾乎總是有外化名字的。

要想外化參數名,請在函數聲明中將外部名字放在內部參數名之前,中間用空格隔開。外部名字可以與內部名字相同,也可以不同。不過在Swift中,外化參數名已經形成了標準,因此有如下規則:在默認情況下,除了第一個參數,所有參數名都會自動外化。這樣,如果需要外化一個參數名,並且它不是第一個參數,並且希望外化名與內部名相同,那麼你什麼都不需要做,Swift會自動幫你實現。

如下是一個函數聲明,該函數會將一個字符串拼接到自身times次:


func repeatString(s:String, #times:Int) -> String {
    var result = \"\"
    for _ in 1...times { result += s }
    return result
}  

該函數的第1個參數只有內部名字,不過第2個參數有一個外部名字,它與內部名字相同,都叫作times。下面是調用該函數的代碼:


let s = repeatString(\"hi\", times:3)  

如你所見,在調用中,外部名作為一個標籤位於實參之前,中間用冒號隔開。

我之前曾經說過,參數的外部名可以與內部名不同。比如,在repeatString函數中,我們將times作為外部名,將n作為內部名。那麼,函數聲明將會如下所示:


func repeatString(s:String, times n:Int) -> String {
    var result = \"\"
    for _ in 1...n { result += s}
    return result
}  

函數體中現在已經看不到times了;times只用作外部名,在調用時使用。內部名是n,也是代碼所引用的名字。

外部名的存在並不意味著調用可以使用與聲明不同的參數順序。比如,repeatString接受一個String參數和一個Int參數,順序就是這樣的。雖然標籤可以消除實參對應於哪個參數的歧義,但調用的順序也需要如此(不過稍後我將給出該規則的一個例外情況)。

repeatString函數說明了默認規則,即第1個參數沒有外部名,其他參數則有。為何說這是默認規則呢?一個原因在於第1個參數通常不需要外部名,因為函數名通常能夠清晰表明第1個參數的含義——就像repeatString函數一樣(重複一個字符串,而該字符串應該由第1個參數提供)。另一個原因也是在實際情況中更為重要的,那就是這個約定使得Swift函數能夠與Objective-C方法交互,而後者採取的就是這種方式。

比如,下面是Cocoa NSString方法的Objective-C聲明:


- (NSString *)stringByReplacingOccurrencesOfString:(NSString *)target
                                        withString:(NSString *)replacement  

該方法接收兩個NSString參數並返回一個NSString。第2個參數的外部名是顯而易見的,即withString。不過第1個參數的名字卻不那麼明顯。一方面,你可以說它是stringByReplacingOccurrencesOfString。另一方面,它實際上並非參數真正的名字;它更像是方法名。實際上,該方法的正式名字是整個字符串stringByReplacingOccurrencesOfString:withString:。不過,Swift函數調用語法通過圓括號將函數名與外部參數名區分開來。因此,如果Swift想要調用這個Objective-C方法,那麼冒號前首先就應該是函數名(位於圓括號之前),然後是第2個實參的標籤(位於圓括號中)。Swift String與Cocoa NSString能夠自動橋接彼此,因此可以在Swift String上調用這個Cocoa方法,如以下代碼所示:


let s = \"hello\"
let s2 = s.stringByReplacingOccurrencesOfString(\"ell\", withString:\"ipp\")
// s2 is now \"hippo\"  

如果函數是你自己定義的(即是你聲明的),並且Objective-C永遠不會調用它(這樣就沒必要遵循Objective-C的要求了),那麼你可以自由改變其默認行為。你可以在自己的函數聲明中做如下事情。

外化第1個參數名

如果想要外化第1個參數名,那麼請將外部名放到內部名之前。這兩個名字可以相同。

修改除第1個參數之外的其他參數名

如果想要修改除第1個參數外的其他參數的外部名,那麼請將所需的外部名放到內部名之前。

防止對除第1個參數外的其他參數進行外化

要想防止對除第1個參數外的其他參數進行外化,請在其前面加上一個下劃線和一個空格:


func say(s:String, _ times:Int) { 

現在在調用這個方法時不能對第2個參數加標籤:


let d = Dog
d.say(\"woof\", 3)  

(這就解釋了本章一開始所作的聲明func sum(x:Int,_y:Int)->Int:這裡阻止了第2個參數名的外化,從而無須提供實參標籤。)

這個函數的名字是什麼?

從技術上來說,一個Swift函數的名字是由圓括號之前的名字加上參數的外部名共同構成的。如果阻止了參數的外部名,那麼可以使用一個下劃線來表示其外部名。結果就是外部參數名會位於圓括號中,後跟一個冒號。比如,函數聲明func say(s:String,times:Int)從技術上來看就是say(_:times:),函數聲明func say(s:String,_times:Int)從技術上來看就是say(_:_:)。這麼表示有點煩瑣,本書也不會這麼使用,不過其優點在於準確和無歧義。