首页 » iOS编程基础:Swift、Xcode和Cocoa入门指南 » iOS编程基础:Swift、Xcode和Cocoa入门指南全文在线阅读

《iOS编程基础:Swift、Xcode和Cocoa入门指南》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 = Dogd.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(_:_:)。这么表示有点烦琐,本书也不会这么使用,不过其优点在于准确和无歧义。