# 函数
## 4.1 函数的定义与调用
函数是一个组织在一起的程序代码集合,用来完成某个特定的功能。为了提高代码的复用性,通常对代码进行抽取,将能够完成同一个任务的代码放置在一起,可作为一个函数使用。给定函数一个名称标识,当执行其任务时,就可以用这个标识来进行函数的调用。
Swift使用关键字func进行函数的定义。当定义一个函数时,可以为其定义一个或多个不同的名称,类型的值,作为函数的输入参数。当该函数完成时,将返回输出定义的类型。
每一个函数都有一个函数名来描述它的功能。通过函数名以及对应类型的参数值,可调用这个函数,函数的参数传递顺序必须与参数列表中的顺序相同。
函数定义的格式如下所示:
~~~
func 函数(参数变量: 类型, 参数变量: 类型...) -> 返回类型
{
程序语句
程序语句
...
return 结果
}
~~~
在下面的 码中,我们定义了一个无参数并且无返回类型的函数:
~~~java
func sayHello()
{
print("Hello,Swift")
}
~~~
函数定义之后,我们可以通过函数名以及对应类型的参数值来调用函数,函数的参数传递的顺序必须与参数列表相同。由于sayHello函数是一个无参函数,所以你可以直接使用函数的名称,以调用该函数。
~~~java
sayHello()
~~~
sayHello函数极为简单,当调用该函数后,将在控制台输出“Hello,Swift”信息。
在下面的代码中,我们定义了拥有两个参数和返回值的函数。所有的参数都被放置在函数名右侧的小括号内。指定的函数的返回值类型以箭头 -> (一个连字符后跟一个右尖括号)以及随后类型的名称作为函数。
~~~java
func sum(num1: Int, num2: Int) -> Int
{
return num1 + num2
}
~~~
## 4.2 为参数设置默认值
在Swift环境中,可以为函数的参数设置默认值。
~~~java
func sum(num1: Int, num2: Int = 2) -> Int
{
print(num1 + num2)
}
~~~
在sum方法的参数声明区域,当添加第二个参数时,在参数类型的右侧添加了一个等号,并在等号后面添加了默认参数值。当调用该函数时,值需要传入第一个参数即可。当然你也可以填写上第二个参数。
~~~java
sum(num1: 1)
sum(num1: 1, num2: 3)
~~~
## 4.3 设置可变的函数参数数量
在定义函数时,如果你不确定参数的数量,可通过在变量类型后面加(...),定义可变参数,一个函数最多能有一个可变参数。为避免在调用函数时产生歧义,一个函数如果有一个或多个参数,并且还有一个可变参数,一定要把可变参数放在最后。
~~~java
func getCount(nums: Int...)
{
print(nums.count)
}
getCount(nums: 1, 2, 3)
getCount(nums: 1, 2, 3, 4, 5, 6)
~~~
## 4.4 函数作为参数和返回类型
Swift中的每个函数都有一个类型,包括函数的参数类型和返回类型。你可以方便的使用此类型,像其他类型一样。
### 4.4.1 函数作为参数
这使得它很容易将函数作为参数,传递给其他的函数,甚至从函数中返回函数类型。
~~~java
func getMin(num1: Int, num2: Int) -> Int
{
var minNum = (num1 < num2) ? num1: num2
return minNum
}
func getMax(num1: Int, num2: Int) -> Int
{
var maxNum = (num1 > num2) ? num1: num2
return maxNum
}
func printResult(mathFunc: (Int, Int) -> Int, num1: Int, num2: Int)
{
print(mathFunc(num1, num2))
}
// 调用的地方
printResult(mathFunc: getMin, num1: 1, num2: 2)
printResult(mathFunc: getMax, num1: 1, num2: 2)
~~~
以上代码分别求出了两个参数中的最小值和最大值,最终的输出结果如下:
~~~
1
2
~~~
### 4.4.2 函数作为返回类型
一个函数除了可被作为另一个函数的参数使用,同时也可以作为其他函数的返回类型。在下面的代码中,通过将函数作为另一个函数的返回类型,实现了与上一个例子中同样的功能。
~~~java
func getMin(num1: Int, num2: Int) -> Int
{
var minNum = (num1 < num2) ? num1: num2
return minNum
}
func getMax(num1: Int, num2: Int) -> Int
{
var maxNum = (num1 > num2) ? num1: num2
return maxNum
}
func chooseFunc(needBigger: Bool) -> (Int, Int) -> Int
{
let func = needBigger ? getMax : getMin
return func
}
// 调用的地方
let func = chooseFunc(needBigger: true)
print(func(2, 3)) // 输出结果为: 3
~~~
## 4.5 元组作为函数的返回类型,实现多个返回值
在日常的开发过程中,可能会遇到这样的场景:当用户通过用户名(一般为邮箱或手机号)和密码来登陆系统后,需要从服务器获取用户的姓名,用户级别和头像信息。对于像这样需要同时返回多条信息的函数,你可以使用元组来组织函数返回的所有内容。
~~~java
func getUserInfo(userId: String) -> (userName: String, userlevel: Int, photoPath: String)
{
let userName = "paul"
let userLevel = 3
let photoPath = "http://www.baidu.com"
return (userName, userLevel, photoPath)
}
~~~
在第一行代码中,定义了一个名为getUserInfo的函数,其包含一个参数userId,通过该参数,可以从服务器查询指定用户的信息,并设置返回类型为(String, Int, String),分别存储用户的姓名,级别,头像路径等信息。
服务器以元组形式返回用户属性信息之后,在控制台打印输出元组的信息即可。
~~~java
let msg = getUserInfo(userId: "0001")
print(msg.0) //输出结果: pual
print(msg.1) //输出结果: 3
print(msg.2) //输出结果: http://www.baidu.com
~~~
## 4.6 使用函数类型
使用函数类型就跟使用其他的类型一样。比如可以定义一个常量或变量,其类型就是函数,而且可以给这个函数赋值。
首先定义一个普通的函数,它包含两个整型参数,然后计算并返回两个参数之和。
~~~java
func getTotal(num1: Int, num2: Int) -> Int
{
return num1 + num2
}
~~~
接着定义了一个newFunc的变量,其类型是两个整型参数并返回整型的函数,并让这个变量指向getTotal函数。
~~~java
let newFunc: (Int, Int) -> Int = getTotal
let result = newFunc(1, 1)
print(result) //输出结果: 2
~~~
在给使用函数类型定义变量时,可以省略函数类型的书写。
~~~java
let newFunc = getTotal
let result = newFunc(1, 1)
print(result) //输出结果: 2
~~~
那么如何使用无参数并且无返回值的函数类型呢?首先定义一个次类型的函数。
~~~java
func printHello()
{
print("Hello, Swift")
}
~~~
printHello函数没有包含任何参数,也没有任何返回值,当需要定义该函数类型的常量或变量时,可以使用以下方式:
~~~java
let a1: ()->() = printHello
a1()
~~~
## 4.7 函数的输入输出参数
一般默认在函数中定义的参数都是常量参数,也就是这个参数只可以查询使用,不能改变它的值。
如果想要声明一个变量参数,可以在参数定义前加 inout 关键字,这样就可以改变这个参数的值。
~~~java
func getName(_ name: inout String)
~~~
此时这个name的值可以在函数在改变。
一般默认的参数传递都是传值调用,而不是传引用。所以传入的参数在函数内改变,并不影响原来的哪个参数,传入的只是这个参数的副本。
当传入的参数作为输入输出参数时,需要在参数名前加 & 符,表示这个值是可以被函数改变的。
~~~java
func swap(_ a: inout Int, _ b : inout Int)
{
let tmp = a
a = b
b = tmp
}
var x = 1
var y = 5
swap(&x, &y)
print("x=\(x),y=\(y)")
~~~
## 4.8 函数的嵌套
一个函数也可以写在其他函数之中,来封装一个嵌套函数,用以实现仅在一定范围内起作用的功能。
~~~java
func getTotal()
{
func getNumber()
{
print("GetNumber")
}
getNumber()
}
getTotal()
~~~
需要注意的是,被嵌套的子函数只能在其父函数的内部使用,在父函数的外部是无法被调用的。