Swift函数基本用法

函数的返回值

在Swift函数中,函数返回值可以被忽略,但定义了返回值的函数必须返回一个值。

多重返回值函数

可以使用元组类型让多个值作为一个复合值从函数中返回。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
 func minMax(array: [Int]) -> (min: Int, max: Int) {
var currentMin = array[0]
var currentMax = array[0]
for value in array[1..<array.count] {
if value < currentMin{
currentMin = value
}else if value > currentMax{
currentMax = value
}
}
return (currentMin, currentMax)
}
print(minMax([18,20,12,54,87,32,21]))
//输出(min: 12, max: 87)
可选元组返回类型

如果函数返回的元组类型可能整个元组都没有值,则可以使用可选的元组返回类型反映整个元组可以是nil的事实。例如:(Int,Int)? 或(Int, String)?

可选元祖类型如(Int,Int)?与元组包含可选类型如(Int?,Int?)是不同的。可选的元组类型,整个元组是可选的,而不是元组中的每个元素值。

在上面的例子中如果不对array参数进行检查,一旦array是个空数组,在访问array时就会触发一个运行时错误。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
func minMax(array: [Int]) -> (min: Int, max: Int)? {
if array.isEmpty {
return nil
}
var currentMin = array[0]
var currentMax = array[0]
for value in array[1..<array.count] {
if value < currentMin{
currentMin = value
}else if value > currentMax{
currentMax = value
}
}
return (currentMin, currentMax)
}

//调用
let bounds = minMax(array: [32,55,87,12,46])
print("the max value of array is \(String(describing: bounds?.max))")

//输出结果
the max value of array is Optional(87)

函数的参数

函数参数标签和参数名称

每个函数都有一个参数标签和一个参数名称。参数标签在调用函数的时候使用;调用的时候需要将函数的参数标签写在对应的参数前面。参数名称在函数的实现中使用。默认情况下,函数参数使用参数名称来作为它们的参数标签。所有的参数都必须有一个独一无二的名字。虽然多个参数拥有同样的参数标签是可能的,但是一个唯一的函数标签能够使你的代码更具有可读性。

1
2
3
4
func someFunction(firstParameterName: Int, secondParameterName: Int) {
// 在函数体内,firstParameterName 和 secondParameterName 代表参数中的第一个和第二个参数值
}
someFunction(firstParameterName: 1, secondParameterName: 2)
指定参数标签
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
func someFunction(argumentLabel parameterName: Int){
//在函数体内,parameterName代表参数值
}
//调用函数时,把argumentLabel放在参数值的签名
someFunction(argumentLabel:123)

//greet函数
func greet(person: String,from hometown: String) -> String {
return "Hello \(person)! Glad you could visit from \(hometown)."
}

//调用
print(greet(person: "Bill", from: "London"))

//输出:Hello Bill! Glad you could visit from London.

忽略参数标签

可以使用下划线来代替一个明确的参数标签

1
2
3
4
5
6
7
//实现
func someFunction(_ firstParameterName: Int, secondParameterName: String) {
print("now I have used _ replace the parameter label")
}

//调用
someFunction(1, secondParameterName: "name")
默认参数值

你可以在函数体中通过给参数赋值来为任意一个参数定义默认值(Deafult Value)。当默认值被定义后,调用这个函数时可以忽略这个参数。

1
2
3
4
5
func someFunction(parameterWithoutDefault: Int, parameterWithDefault: Int = 12) {
// 如果你在调用时候不传第二个参数,parameterWithDefault 会值为 12 传入到函数体中。
}
someFunction(parameterWithoutDefault: 3, parameterWithDefault: 6) // parameterWithDefault = 6
someFunction(parameterWithoutDefault: 4) // parameterWithDefault = 12

将不带有默认值的参数放在函数参数列表的最前。一般来说,没有默认值的参数更加的重要,将不带默认值的参数放在最前保证在函数调用时,非默认参数的顺序是一致的,同时也使得相同的函数在不同情况下调用时显得更为清晰。

可变参数

一个可变参数可以接零个或多个值。函数调用时,你可以用可变参数来指定函数参数可以被传入不确定数量的输入值。通过在变量类型名后面加入(…)的方式来定义可变参数。可变参数的传入值在函数体中变为此类型的一个数组。

一个函数最多只能拥有一个可变参数。

1
2
3
4
5
6
7
8
9
10
11
12
13
//一个叫做 numbers 的 Double... 型可变参数,在函数体内可以当做一个叫 numbers 的 [Double] 型的数组常量。

func arithmeticMean(_ numbers: Double...) -> Double {
var total: Double = 0
for number in numbers {
total += number
}
return total / Double(numbers.count)
}
arithmeticMean(1, 2, 3, 4, 5)
// 返回 3.0, 是这 5 个数的平均数。
arithmeticMean(3, 8.25, 18.75)
// 返回 10.0, 是这 3 个数的平均数。
输入输出参数(In-Out Parameters)

函数参数默认是常量。在函数体中如果需要更改参数值,应该将这个参数定义为输入输出参数,否则将会导致编译错误。

使用形式:在参数定义前加inout关键字。

注意:

只能传递变量给输入输出参数。不能传入常量或字面量,因为这些类型是不能被修改的。当传入的参数作为输入输出参数时,需要在参数名前加&符号,表示这个值可以被函数修改。另外,输入输出参数不能有默认值,而且可变参数不能用inout标记。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
func swapTwoInts(aInt a: inout Int, bInt b: inout Int) {
let temp = a
a = b
b = temp
}
func swapTwoDouble(a: inout Double, b: inout Double) {
let temp = a
a = b
b = temp
}

//调用
var someInt = 3
var anotherInt = 5
swapTwoInts(aInt: &someInt, bInt: &anotherInt)

var someDouble = 2.0
var anotherDouble = 1.4
swapTwoDouble(a: &someDouble, b: &anotherDouble)

注意:输入输出参数和返回值是不一样的。上面的swapTwoInts函数并没有定义任何返回值,但仍然修改了someIntanotherInt的值。输入输出参数是函数对函数体外产生影响的另一种方式。

函数类型

函数类型定义:(参数类型1, 参数类型2, …) ->返回值类型

函数类型是一种引用类型,类似于函数指针。可以将函数类型应用于任何使用类型的地方:变量、参数、返回值。

1
2
3
4
5
6
func addTwoInts(_ a: Int, _ b: Int) -> Int {
return a + b
}
func multiplyTwoInts(_ a: Int, _ b: Int) -> Int {
return a * b
}

上面的两个函数的类型都是(Int,Int) -> Int,可以理解为:这个函数类型有两个Int型的参数并返回一个Int型的值。

使用函数类型

使用函数类型就像使用其他类型一样。例如你可以定义一个类型为函数的常量或变量,并将适当的函数赋值给它:

1
var mathFunction: (Int,Int) ->Int = addTwoInts

这段代码表示:定义一个叫做mathFunction的变量,类型是“一个有两个Int型的参数并返回一个Int型的值的函数”,并让这个新变量指向addTwoInts函数

1
2
print("Result:\(mathFunction(2,3))")
//打印:Result:5

有相同匹配类型的不同函数可以被赋值给同一个变量,就像非函数类型的变量一样。

1
2
3
mathFunction = multiplyTwoInts
print("Result:\(mathFunction(2,3))")
//打印:Result:6

像其他类型一样,当赋值一个函数给常量或变量时,可以让Swift来推断其函数类型:

1
2
let anotherFunction = addTwoInts
//anotherFunction被推断为(Int,Int) -> Int类型
函数类型作为参数类型

示例:

1
2
3
4
5
6
7
//定义一个printMathResult(_:_:_:)函数,它有三个参数,其中第一个参数是mathFunction,类型是(Int,Int) -> Int,你可以传入任何这种类型的函数,第二个和第三个参数叫a,b。
func printMathResult(_ mathFunction: (Int, Int) -> Int, _ a: Int,_ b: Int){
print("Result: \(mathFunction(a,b))")
}

//printMathResult(_:_:_:)函数的作用就是输出另一个适当类型的数学函数的调用结果。它不关心函数是如何实现的,只关心传入的函数是不是一个正确的类型。
printMathResult(addTwoInts,3,5)

函数类型

形式:在返回类型处写一个完整的函数类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
func stepForward(_ input: Int) -> Int {
return input + 1
}
func stepBackward(_ input: Int) -> Int {
return input - 1
}

func chooseStepFunction(backward: Bool) -> (Int) -> Int {
return backward ? stepBackward : stepForward
}

//调用
var currentValue = 3

let moveNearToZero = chooseStepFunction(backward: currentValue > 0)
//moveNearToZero指向了stepBackward函数
while currentValue != 0 {
print("currentValue is \(currentValue)")
currentValue = moveNearToZero(currentValue)
}

嵌套函数

定义在别的函数体中的函数被称为嵌套函数。定义在全局域中的函数被称为全局函数。

默认情况下,嵌套函数是对外界不可见的,但是可以被它们的外围函数(enclosing function)调用。一个外围函数也可以返回它的某一个嵌套函数,使得这个函数可以在其他域中被使用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
func chooseNewStep(backward: Bool) -> (Int) -> Int {
func stepFor(input: Int) -> Int{
return input + 1
}
func stepBack(input: Int) ->Int{
return input - 1
}
return backward ? stepBack : stepFor
}

//调用
var cueentStep = -5
let moveStep = chooseNewStep(backward: cueentStep > 0)
while cueentStep != 0 {
print("currentStep is \(cueentStep)")
cueentStep = moveStep(cueentStep)
}

提前退出函数

在函数中可以使用guard语句提前退出函数。跟if…else…语句类似,guard语句会根据某个表达式返回的布尔值结果来执行代码。不同之处是,如果某些条件没有满足,可以用guard语句提前退出函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//guard语句一般格式
guard 条件表达式 else{
不满足条件时执行的代码
return //提前退出函数
}

//示例:
func greetByMiddleName(fromFullName name:(first: String, middle: String, last: String)){
guard let middleName = name.middle else{
print("Hey there!")
return
}
print("Hey\(middleName)")
}

greetByMiddleName(fromFullName:("Matt","Danger","Mathias"))