![Swift 5从零到精通iOS开发训练营](https://wfqqreader-1252317822.image.myqcloud.com/cover/144/44510144/b_44510144.jpg)
5.1 函数的基本应用
在数学中,函数有3要素:定义域、对应关系和值域。在编程中,抛开函数的实现,在声明函数时也有3要素:参数、返回值和函数名。参数和返回值决定函数的类型,参数数量和类型完全相同,同时返回值类型也相同的函数则为同类型函数。Swift语言中,使用func关键字来声明函数,一个完整的函数声明和实现应该符合如下格式:
func methodName(param1,param2,…)->returnValue{实现部分}
methodName需要编写为函数名称,之后跟的小括号中需要设置函数的参数类型和个数,多个参数使用逗号进行分割。参数列表后面使用符号“->”来连接返回值类型。至此,函数的声明部分就完成了。如果要对函数进行实现,在后面追加大括号,里面为函数的实现代码。如果一个函数没有返回值,也可以将参数列表后面的部分省略。在调用函数时,直接使用函数名来进行调用。
5.1.1 函数的创建与调用
使用Xcode开发工具创建一个名为Function的Playground文件,在其中编写如下示例代码:
![](https://epubservercos.yuewen.com/21D3CA/23721705709589206/epubprivate/OEBPS/Images/Figure-P80_16687.jpg?sign=1738858177-QUzBlvi54OjtazO8g5hVGvUufpryXUUy-0-b33f35541e8a7b4258a956c2b1eb5201)
参数列表中的参数需要指定参数名和参数类型,也可以编写无参的函数,为空即可,示例代码如下:
![](https://epubservercos.yuewen.com/21D3CA/23721705709589206/epubprivate/OEBPS/Images/Figure-P80_10173.jpg?sign=1738858177-doQkc0LnI2TB7OqJ14KgegZzQkG2ygTa-0-10d56aea161c2a1c04d79348afc3ffe9)
如果函数不需要返回值,可以选择返回Void或者直接省略返回值部分,示例代码如下:
![](https://epubservercos.yuewen.com/21D3CA/23721705709589206/epubprivate/OEBPS/Images/Figure-P81_16688.jpg?sign=1738858177-rqHvXVCLPmFoUt7zOQbGR6o2epxOQO2s-0-1a662bef7e790c902f0d635595a1d054)
还有一种特殊情况,原则上函数的返回值只能有一个,在实际开发中,如果需要返回多个值,通常会采用复合类型来处理。在Objective-C语言中,由于不支持元组类型,要返回多个值时,会采用返回数组或者字典的方式。在Swift语言中,可以用元组来达到这样的效果,模拟一个数据查询的函数,这个函数将通过传入一个数据ID来进行数据查询操作,并返回查询状态和具体的数据,示例代码如下:
![](https://epubservercos.yuewen.com/21D3CA/23721705709589206/epubprivate/OEBPS/Images/Figure-P81_16689.jpg?sign=1738858177-0S07kkOWgrB9lHmzAeW17MEAc96tlOAw-0-4ca487105f776871f717e08d97849e9c)
Swift语言中的函数还有一个使用技巧,开发者可以通过返回Optional类型值来标识函数的执行是否成功,在调用函数时使用if-let结构进行安全性检查,示例代码如下:
![](https://epubservercos.yuewen.com/21D3CA/23721705709589206/epubprivate/OEBPS/Images/Figure-P81_10180.jpg?sign=1738858177-um1naroAqftcdsMUAddxMgxK7ZMcqA1t-0-4b3e7885b6d2def6c31f3a76a7c1bf0d)
5.1.2 关于函数的参数名
有编程经验的读者可能会发现各个编程语言有一些特点,以函数的参数名为例,在Objective-C中,实际上函数的参数名是隐含于函数名称中的,示例如下:
//Objective-C语言中函数的风格 -(void)getDataFromDataID:(NSString*)dataID{ } //对函数进行调用 [self getDataFromDataID:@"1101"];
Objective-C这种风格的函数写法有一个很大的优点,开发者在调用函数时,根据函数名中的信息就可以推断出参数的意义,如以上代码所示,getDataFromDataID很容易使开发者联想到此参数需要传递数据的ID值。这里会产生一个问题,函数名将变得非常冗长,编码界面将变得十分拥挤。在Java中,参数名是直接添加在参数列表中的,示例如下:
//Java语言中函数的风格 private void getMyData(String dataID){ } getMyData("1101");
通过比较Java与Objective-C的函数风格,可以发现Java语言简练得多,但同时也有缺陷:在调用函数时,函数参数列表中的参数并没有一个参数名标识,这样开发者在调用函数或者检查代码时,不能一目了然地明白各个参数的意义。在参数很多的情况下,这个问题就变得尤为突出。
Swift语言中的函数风格借鉴了Objective-C与Java的优势和劣势,引入了参数的内部命名与外部命名概念。内部命名在函数实现时使用,外部命名在函数调用时使用。上面所有例子编写的函数中,参数名都是内部命名,开发者若不设置参数的外部命名,则默认函数参数的外部命名与内部命名相同。因此开发者在调用函数时,传入的参数前面都有一个参数名标注,示例如下:
![](https://epubservercos.yuewen.com/21D3CA/23721705709589206/epubprivate/OEBPS/Images/Figure-P82_16692.jpg?sign=1738858177-t2Q60gq68ynJ1PcHOGKMeaeiYLI2HrZU-0-05a7a0e37b8a323377ecc5f4db58fa7e)
在声明函数时,也可以在内部命名的前面再添加一个名称作为参数的外部命名,示例如下:
![](https://epubservercos.yuewen.com/21D3CA/23721705709589206/epubprivate/OEBPS/Images/Figure-P82_16693.jpg?sign=1738858177-4VWobZPxRAzHIqw5DBdZ23nYCOv2YoFh-0-4e05ae54dcea2ea3134e7b2c47e4010d)
有了Swift中参数内部名称与外部名称的语法规则,开发者可以十分灵活地编写函数。参数的外部名称会在调用函数时标识参数,这样既简化了函数名,又能很好地帮助开发者理解每个参数的意义,并且这种语法的优势在进行函数重载操作时会更大,在后面讲解函数重载的章节中,读者就能体会到。
Swift语言也支持省略函数参数的外部名称,默认函数参数的外部名称与内部名称相同,开发者可以使用匿名变量标识符“_”来对外部名称进行省略,示例如下:
![](https://epubservercos.yuewen.com/21D3CA/23721705709589206/epubprivate/OEBPS/Images/Figure-P83_10194.jpg?sign=1738858177-cd34bjNMe8huE0E8AqvJFckYWA1VxnXo-0-2f04f6e50b99e5da48a3dfd29881e6c1)
5.1.3 函数中参数的默认值、不定数量参数与inout类型参数
在进行函数调用时,每个参数都必须要传值,这句话其实并不十分准确,应该说每个参数都必须有值。除了在调用时为参数传值外,Swift语言中函数的参数也支持设置默认值。需要注意的是,如果函数的某个参数设置了默认值,那么开发者在调用函数的时候,可以传此参数的值,也可以不传此参数的值,但是参数的位置要严格对应。示例如下:
![](https://epubservercos.yuewen.com/21D3CA/23721705709589206/epubprivate/OEBPS/Images/Figure-P83_16694.jpg?sign=1738858177-NtLvKBTB6kKnPp4vWQpBHTcfAmAmjuwG-0-f608dbdc5f0130988e3a955a6fc56d37)
在开发中还有一种情况也十分常见,有时候开发者需要编写参数个数不定的函数,例如打印函数print(),其中传入参数的数量就是不确定的。对于这类函数的编写,Swift也对它做了很好的支持。编写一个函数,传入不定个数的整数值,打印其相加后的结果,示例代码如下:
![](https://epubservercos.yuewen.com/21D3CA/23721705709589206/epubprivate/OEBPS/Images/Figure-P83_16695.jpg?sign=1738858177-t3TTpKvtZoqO0VRgjZnBLRnW2ZPhPaD2-0-f0283a9b79a262b22ee5e37c45f60934)
实际上,在Swift语言中,在某个参数类型的后面追加符号“…”,则会将此参数设置为数量可变。在函数内部,开发者传递的值会被包装成一个集合类型赋值给对应参数。需要注意,传递的参数类型必须相同,并且可以传递多组数量可变的参数,不同参数之间参数类型可以不同,示例如下:
![](https://epubservercos.yuewen.com/21D3CA/23721705709589206/epubprivate/OEBPS/Images/Figure-P84_16696.jpg?sign=1738858177-AraRvjMQNOXfg6UeyTgcdVZ7cVOW6KdS-0-cb160358d15e77fc048aa5d3f662a70b)
Swift语言支持设置函数参数的默认值,支持传递数量不定的参数,开发者在编写代码时灵活运用函数可以达到事半功倍的效果。
关于Swift语言的参数传递,还有这样一个特点:传递的如果是值类型的参数,那么参数值在传递进函数内部时会将原值复制为一份常量,且在函数内不可以修改。关于值类型和引用类型的相关知识,后面章节会详细介绍,这里读者只需要了解:类属于引用类型,而基本数据类型、枚举和结构体都属于值类型。对于值类型参数,如果开发者在函数内部修改参数的值,编译器会直接报错,示例代码如下:
//错误示范 //func myFunc12(param:Int){ // param+=1 //}
如果在开发中真的需要在函数内部修改传递参数的变量的值,可以将此参数声明为inout类型,示例代码如下:
![](https://epubservercos.yuewen.com/21D3CA/23721705709589206/epubprivate/OEBPS/Images/Figure-P84_16698.jpg?sign=1738858177-XDMnxSGuLV95xMcexGZx2oL9fzaoSphQ-0-c8271d92fcfe6d6367028eac6068e522)
上面的演示代码中将参数param声明为inout类型,在传参时需要使用“&”符号,这个符号将传递参数变量的内存地址。