iOS开发之Swift篇(6)—— 函数

版本

Xcode 11.0
Swift 5.1

函数定义与调用

函数是一段完成特定任务的独立代码片段。
当你定义一个函数时,你可以定义一个或多个有名字和类型的值,作为函数的输入,称为参数,也可以定义某种类型的值作为函数执行结束时的输出,称为返回类型。
函数可以没有参数, 也可以没有返回类型。
一般写法

func 函数名(形参1, 形参2) -> 返回类型 {
    
    
    // 函数体
}

举个例子:

// 定义
func funcName(name: String, address: String) -> String {
    
    
    return name + "住在" + address
}

// 调用
print(funcName(name: "小明", address: "和磡村"))
// 打印 小明住在和磡村

参数与返回值

1. 无参数

// 无参数
func sayHello() -> String {
    
    
    return "Hello, world"
}
print(sayHello())
// 打印 Hello, world

尽管这个函数没有参数,但是定义中在函数名后还是需要一对圆括号。当被调用时,也需要在函数名后写一对圆括号。

2. 多参数

// 多参数
func teamMember(name1: String, name2: String, name3: String) -> String {
    
    
    return "团队成员有" + name1 + "," + name2 + "," + name3
}
print(teamMember(name1: "小明", name2: "小红", name3: "小黑"))
// 打印 团队成员有小明,小红,小黑

3. 无返回值

// 无返回值
func printTeamMember(name1: String, name2: String, name3: String) {
    
    
    print("团队成员有\(name1), \(name2), \(name3)")
}
printTeamMember(name1: "小明", name2: "小红", name3: "小黑")
// 打印 团队成员有小明, 小红, 小黑

严格地说,即使没有明确定义返回值,该函数仍然返回一个值。没有明确定义返回类型的函数返回一个 Void 类型特殊值,该值为一个空元组,写成 ()。

4. 多重返回值 (返回元组类型)
下例中定义了一个名为 minMax(array:) 的函数,作用是在一个 Int 类型的数组中找出最小值与最大值。

// 定义
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)
}

// 调用
let bounds = minMax(array: [8, -6, 2, 109, 3, 71])
print("min is \(bounds.min) and max is \(bounds.max)")
// 打印“min is -6 and max is 109”

5. 可选元组返回类型
如果函数返回的元组类型有可能整个元组都“没有值”,你可以使用可选的 元组返回类型反映整个元组可以是 nil 的事实。你可以通过在元组类型的右括号后放置一个问号来定义一个可选元组,例如 (Int, Int)? 或 (String, Int, Bool)?

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

前面的 minMax(array:) 函数返回了一个包含两个 Int 值的元组。但是函数不会对传入的数组执行任何安全检查,如果 array 参数是一个空数组,如上定义的 minMax(array:) 在试图访问 array[0] 时会触发一个运行时错误。
为了安全地处理这个“空数组”问题,将 minMax(array:) 函数改写为使用可选元组返回类型,并且当数组为空时返回 nil:

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)
}

if let bounds = minMax(array: [8, -6, 2, 109, 3, 71]) {
    
    
    print("min is \(bounds.min) and max is \(bounds.max)")
}
// 打印“min is -6 and max is 109”

参数标签和参数名称

1. 参数标签
文初的例子我们可以这样写:

// 函数标签
func funcName1(student name: String, liveIn address: String) -> String {
    
    
    return "学生" + name + "住在" + address
}
print(funcName1(student: "小明", liveIn: "和磡村"))
// 打印 学生小明住在和磡村

参数 name 前面加了个标签 student, 参数 address 前面加了个标签 liveIn.
加标签前, 调用函数使用的是参数名称; 加标签后, 必须使用参数标签.

2. 忽略参数标签
如果你不希望为某个参数添加一个标签,可以使用一个下划线(_)来代替一个明确的参数标签。

// 忽略函数标签
func funcName2(_ name: String, _ address: String) -> String {
    
    
    return "学生" + name + "住在" + address
}
print(funcName2("小明", "和磡村"))
// 打印 学生小明住在和磡村

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

// 默认参数值
func funcName3(name: String, address: String = "和磡村") -> String {
    
    
    return "学生" + name + "住在" + address
}
print(funcName3(name: "小明"))
// 打印 学生小明住在和磡村
print(funcName3(name: "小明", address: "白石洲"))
// 打印 学生小明住在白石洲

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

// 可变参数
func funcName4(names: String..., address: String) -> String {
    
    
    var str = "学生"
    for name in names[0...] {
    
    
        str.append(name)
        str.append(" ")
    }
    str.append("住在")
    str.append(address)
    return str
}
print(funcName4(names: "小明", "小红", "小黑", address: "和磡村"))
// 打印 学生小明 小红 小黑 住在和磡村


一个函数中只能有一个可变参数, 旧版Swift可变参数只能是最后一个参数, 新版不限制.

5. 输入输出参数
函数参数默认是常量。
定义一个输入输出参数时,在参数定义前加 inout 关键字, 并且传入参数时需要在参数名前加 & 符。

// 输入输出参数
func assignment(number1: inout Int, number2: inout Int) {
    
    
    number1 = 20
    number2 = 30
}
var int1 = 0, int2 = 0
assignment(number1: &int1, number2: &int2)
print("int1 = \(int1), int2 = \(int2)")
// 打印 int1 = 20, int2 = 30

函数类型

每个函数都有种特定的函数类型,函数的类型由函数的参数类型和返回类型组成。
例如:

func addTwoInts(_ a: Int, _ b: Int) -> Int {
    
    
    return a + b
}

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

又如:

func printHelloWorld() {
    
    
    print("hello, world")
}

这个函数的类型是:() -> Void,或者叫“没有参数,并返回 Void 类型的函数”。

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

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

addTwoInts 和 mathFunction 有同样的类型,所以这个赋值过程在 Swift 类型检查(type-check)中是允许的。
现在,你可以用 mathFunction 来调用被赋值的函数了:

print("Result: \(mathFunction(2, 3))")
// Prints "Result: 5"

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

let anotherMathFunction = addTwoInts
// anotherMathFunction 被推断为 (Int, Int) -> Int 类型

2. 函数类型作为参数类型
你可以用 (Int, Int) -> Int 这样的函数类型作为另一个函数的参数类型。这样你可以将函数的一部分实现留给函数的调用者来提供。
下面是另一个例子,正如上面的函数一样,同样是输出某种数学运算结果:

func printMathResult(_ mathFunction: (Int, Int) -> Int, _ a: Int, _ b: Int) {
    
    
    print("Result: \(mathFunction(a, b))")
}
printMathResult(addTwoInts, 3, 5)
// 打印“Result: 8”

这个例子定义了 printMathResult(::: ) 函数,它有三个参数:第一个参数叫 mathFunction,类型是 (Int, Int) -> Int,你可以传入任何这种类型的函数;第二个和第三个参数叫 a 和 b,它们的类型都是 Int,这两个值作为已给出的函数的输入值。
当 printMathResult(
::: ) 被调用时,它被传入 addTwoInts 函数和整数 3 和 5。它用传入 3 和 5 调用 addTwoInts,并输出结果:8。

3. 函数类型作为返回类型
你可以用函数类型作为另一个函数的返回类型。你需要做的是在返回箭头(->)后写一个完整的函数类型。
下面的这个例子中定义了两个简单函数,分别是 stepForward(: ) 和 stepBackward(: )。stepForward(: ) 函数返回一个比输入值大 1 的值。stepBackward(: ) 函数返回一个比输入值小 1 的值。这两个函数的类型都是 (Int) -> Int:

func stepForward(_ input: Int) -> Int {
    
    
    return input + 1
}
func stepBackward(_ input: Int) -> Int {
    
    
    return input - 1
}

如下名为 chooseStepFunction(backward:) 的函数,它的返回类型是 (Int) -> Int 类型的函数。chooseStepFunction(backward:) 根据布尔值 backwards 来返回 stepForward(: ) 函数或 stepBackward(: ) 函数:

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

你现在可以用 chooseStepFunction(backward:) 来获得两个函数其中的一个:

var currentValue = 3
let moveNearerToZero = chooseStepFunction(backward: currentValue > 0)
// moveNearerToZero 现在指向 stepBackward() 函数。

上面这个例子中计算出从 currentValue 逐渐接近到0是需要向正数走还是向负数走。currentValue 的初始值是 3,这意味着 currentValue > 0 为真(true),这将使得 chooseStepFunction(: ) 返回 stepBackward(: ) 函数。一个指向返回的函数的引用保存在了 moveNearerToZero 常量中。
现在,moveNearerToZero 指向了正确的函数,它可以被用来数到零:

print("Counting to zero:")
// Counting to zero:
while currentValue != 0 {
    
    
    print("\(currentValue)... ")
    currentValue = moveNearerToZero(currentValue)
}
print("zero!")
// 3...
// 2...
// 1...
// zero!

嵌套函数

到目前为止本章中你所见到的所有函数都叫全局函数(global functions),它们定义在全局域中。你也可以把函数定义在别的函数体中,称作 嵌套函数(nested functions)。
默认情况下,嵌套函数是对外界不可见的,但是可以被它们的外围函数(enclosing function)调用。一个外围函数也可以返回它的某一个嵌套函数,使得这个函数可以在其他域中被使用。
你可以用返回嵌套函数的方式重写 chooseStepFunction(backward:) 函数:

func chooseStepFunction(backward: Bool) -> (Int) -> Int {
    
    
    func stepForward(input: Int) -> Int {
    
     return input + 1 }
    func stepBackward(input: Int) -> Int {
    
     return input - 1 }
    return backward ? stepBackward : stepForward
}
var currentValue = -4
let moveNearerToZero = chooseStepFunction(backward: currentValue > 0)
// moveNearerToZero now refers to the nested stepForward() function
while currentValue != 0 {
    
    
    print("\(currentValue)... ")
    currentValue = moveNearerToZero(currentValue)
}
print("zero!")
// -4...
// -3...
// -2...
// -1...
// zero!

猜你喜欢

转载自blog.csdn.net/u012078168/article/details/103700671