说说swift方法里的参数标签

方法参数标签在其他语言里很少见,如果没有oc的经验,直接看到swift的代码标签会有些懵圈.

上一段swift2的代码

func sendMessage(msg: String){
  // send msg
}
var msg = "hello"
sendMessage(msg)

一个参数的方法似乎与其他语言没什么不同,如果方法有两个参数就得写成这样了

func sendMessage(msg: String, to sb: String){
  // send msg to sb
}
var msg = "hello"
var sb = "bob"
sendMessage(msg, to:sb) 

为什么sendMessage后面的参数会变这样,感觉乱乱的. 这个原因主要是因为swift的语言设计的时候的主要目标是替代现有的objective-c,语言的更替最需要考虑的就是语言多年积累的生态,各种库和框架. 所以swift需要兼容这些.

再来看一段obj-c的代码就会更容易明白为什么要这么设计了.

[[NSNotificationCenter defaultCenter] addObserver:observer
                                         selector:aSelector
                                             name:LKLNFT_APP_INITIATIVE_COMPLETED
                                           object:nil];

参数加上标签可以更清楚的说明参数的用意,很显然,obj-c中的表达形式更优雅一些.

同时object-c中方法并不是简单通过方法名来区别不同的方法调用的.而是通过叫 selector来区分的.什么是selector

,看下面几个同名但参数不同的方法.

-(void) sendMessage {}

-(void) sendMessage:(NSString*) msg {}

-(void) sendMessage:(NSString*) msg to:(NSString*) sb {}

三个方法,虽然方法名相同,参数不同,但其实是三个不同的方法,在obj-c中这三个方法调用实际上是通过

sendMessage

sendMessage:

sendMessage:to:

来区分的.方法如果有参数,那么方法名充当了第一个参数的标签,也可 以说第一个参数是省略了标签的.这样的设计,会让代码读起来更像一句人话. 同时因为objc-c的语法让这样的定义有对称,有美感.

但是到了swift中,方法定义是跟大多数语言一样,方法名加上括号以及括号中的参数,这样的语法设计很显然无法保持 上面说的对称与美感,为了兼容obj-c,总让人看起来怪怪的.

sendMessage(msg, to:sb)

从swift3开始,对这个做了一些调整,就是方法的第一个参数不再是默认省略标签了, 所有的参数在方法定义都必须显示声明标签 ,如果调用的时候不想输入标签,那也要使用_ 进行声明.

func send(msg msg:String, to sb:String){}
send(msg:msg, to:sb)

//如果不想输入参数标签,使用 _ 进行声明,这样就更类c语言的调用一样的风格了
func send(_ msg:String, _ sb:String){}
send(msg,sb)

到这里,基本明白swift为什么会有方法标签了,如果没有obj-c的兼容问题,估计语言的设计者不会保留标签这个特性了,毕竟现在的IDE或是编辑器都可以很方便的显示参数的相关信息,并不需要通过语言特性来实现,有时候对开发者反而是个负担. 好在swift3的做法也基本能自圆其说了,但仍然无法有obj-c那样的对称美了. 但想到obj-c是一个80年代就出生的语言,当年连个象样的编辑器都不多,别说IDE了.所以这样的别致设计还真是让人眼前一亮.

swift5补充: 有三种方式,但是一般最常用 的就是前两种

//第一种
//定义,编译器默认生成跟内部参数一样的外部名称 func send(msg msg: String, to to:String){}
func send(msg:String, to:String){}  
send(msg: "hello", to: "bob")

//第二种
//通过 _ 省略外部名称,调用方式就跟其他语言一样
func send(_ msg:String, _ to: String){}
send("hello", "bob")

//第三种 以前是objc最常用的,现在反而最不常用
func send(exMsg msg:String, exTo to:String){}
send (exMsg:"hello", exTo:"bob")