3.函数

83 阅读5分钟

1.函数的定义

// 无返回值的情况
func sayHello() {
    print("Hello")
}

func sayHello1()->(){
    print("Hello2")
}

func sayHello3()-> Void{
    print("Hello3")
}

形参是let,也只能是let

2.隐式返回

如果整个函数就一个单一表达式,那么函数会隐式返回这个表达式.和js中的箭头函数是一样的

func sum1(v1:Int, v2:Int) -> Int {
    v1 + v2
}

sum1(v1: 20, v2: 30)

3.返回元祖:实现多返回值

func calculate(v1: Int, v2: Int) -> (sum: Int, difference:Int, average:Int) {
    let sum = v1 + v2
    return (sum,v1-v2,sum >> 1)
}

let result = calculate(v1: 20, v2: 10)
print("sum",result.sum)

4.函数的文档注释

/// 求和【概述】
///
/// 将2个整数相加【更详细的描述】
///
/// - Parameter v1: 第一个整数
/// - Parameter v2: 第二个整数
/// - Returns: 2个整数的和
///
/// - Note:传入2个整数即可【批注】

func sum(v1:Int,v2:Int) ->Int {
    return v1 + v2
}
sum(v1: 10, v2: 20)

5.参数标签 (Argument Label)

可修改参数标签

func gotoWork(at time: String){
    print("this time is \(time)")
}
gotoWork(at: "08:00")

//可以使用下划线 _ 省略参数标签
func sum3(_ v1: Int, _ v2: Int) -> Int {
    v1 + v2
}
sum3(30, 30)

6.默认参数值(Default Parameter Value)

// 参数可以有默认值
func check(name: String = "nobody", age:Int, job:String = "none"){
    print("name=\(name),age=\(age),job=\(job)")
}
check(name: "Jack", age: 20, job: "Doctor")
check(age:19, job: "cook")
check(age: 10)
//C++ 的默认参数值有个限制:必须从右边往左设置。由于Swift拥有参数标签,因此并没有此类限制,但是在省略参数标签时,需要特别注意,避免出错
func test(_ first:Int = 10, middle:Int,_last:Int = 30){

}
test(middle:20)

7.可变参数(variadic parameter)

func sum(_ numbers:Int...) -> Int {
    var total = 0
    for num in numbers {
        total += num
    }
    return total
}

sum(10,20,30,40,50)
  • 一个函数最多只能有一个可变参数
  • 紧跟在可变参数后面的参数不能省略参数标签

swift 自带的print函数使用

func test(_ numbers: Int..., string: String, _ other:String){
}

test(10,20,30,string:"Jack","Rose")

8.输入输出参数(In-Out Parameter)

  • 可以使用inout 定义一个输入输出参数:可以在函数内部修改外部实参的值 注意点主要有以下几点:
  1. 可变参数不能标为inout
  2. inout参数不能有默认值
  3. inout 参数只能传入可以被多次赋值的
  4. inout 参数的本质是地址传递(引用传递)
func swapValues(_ v1:inout Int, _ v2:inout Int){
    let tmp = v1
    v1 = v2
    v2 = tmp
}

var num1 = 10
var num2 = 20
swapValues(&num1, &num2)
print(num1,num2)

9.函数重载(Function overload)

什么叫函数重载,函数名相同,当参数个数,或者参数类型不同,或者参数标签不同的叫函数重载.这里需要注意的是返回值类型与函数重载无关

  1. 参数个数不同
func sum(v1:Int, v2:Int) -> Int {
    v1 + v2
}

func sum (v1:Int, v2:Int, v3:Int) -> Int {
    v1 + v2 + v3
}

2.参数类型不同

func sum(v1:Int, v2:Double)->Double {
    Double(v1) +v2
}

func sum(v1:Double, v2:Int)->Double {
    v1 +Double(v2)
}

3.参数标签不同

func sum(_ v1:Int, _ v2:Int) ->Int {
    v1 + v2
}

func sum(a: Int,b: Int) ->Int {
    a + b
}

其他细节

  1. 返回值类型与函数重载无关
func sum(v1: Int, v2:Int)->Int {v1 + v2}
//func sum(v1: Int, v2:Int) {}
//sum(v1:10, v2:20)

2.默认参数值和函数重载产生一起使用产生二义性,编译器并不会报错(在c++中会报错)

func sum(v1: Int, v2:Int)->Int {
    v1 + v2
}

func sum(v1:Int, v2:Int, v3:Int = 10) ->Int {
    v1 + v2 + v3
}

sum(v1:10,v2:20)

3.可变参数,省略参数标签,函数重载一起使用产生二义性时,编译器有可能会报错

func sum(v1:Int, v2:Int) -> Int {
    v1 + v2
}

func sum (_ v1:Int, _ v2:Int) -> Int {
    v1 + v2
}


func sum(_ numbers: Int ...)->Int {
    var total = 0
    for number in numbers {
        total += number
    }
    return total
}

sum(10,20)

10.内联函数

如果开启了编译器优化(Release模式默认会开启优化),编译器会自动将某些函数变成内联函数

func testPrint() {
    print("testPrint")
}
testPrint()

大白话解释下什么是内联函数?对于下面的函数来说,其实就是编译器直接会将testPrint()替换成print("testPrint"),前面的func testPrint() 直接没有了

特殊情况

哪些函数不会被自动内联?

  1. 函数体比较长 
  2. 包含递归调用
  3. 包含动态派发

永远不会被内联的情况

@inline(never) func test1(){
    print("test")
}

开启编译器优化后,即使代码很长,也会被内联(递归调用函数,动态派发的函数除外)

@inline(__always) func test(){
    print("test")
}

在Release模式下,编译器已经开启优化,会自动决定哪些函数需要内联,因此没有必要使用 @inline

11.函数类型(Function Type)

每一个函数都是有类型的,函数类型由形式参数类型,返回值类型组成

func test(){}

上面函数的类型是 // ()->void 或者 ()->()

func sum(a:Int,b:Int)->Int {
    a + b
}

上面函数的类型是 (Int, Int) -> Int

函数类型作为函数参数

func sum(v1: Int, v2:Int) -> Int {
    v1 + v2
}

func difference(v1: Int, v2:Int) -> Int {
    v1 - v2
}

func printResult(_ mathFn:(Int,Int)-> Int, _ a: Int, _ b:Int){
    print("Result:\(mathFn(a,b))")
}
printResult(sum, 5, 2)
printResult(difference, 5, 2)

函数类型作为函数的返回值

func next(_ input: Int)->Int {
    input + 1
}

func previous(_ input:Int)->Int {
    input - 1
}

func forward(_ forward:Bool)-> (Int)->(Int) {
    forward ? next : previous
}

forward(true)(3)
forward(false)(3)

返回值是函数类型的函数,叫做高阶函数

12.typealias 用来给类型起别名

typealias Byte = Int8
typealias Short = Int16
typealias Long = Int64
typealias Date = (year: Int, month:Int, day:Int)

func test(_ date:Date){
    print(date.0)
    print(date.year)
}

test((2021,9,10))

按照swift 标准库的定义,Void 就是空元祖()

Public typealias Void = ()

13.嵌套函数(Nested Function)

func forward(_ forward:Bool) ->(Int)->(Int) {
    func next(_ input:Int) -> Int {
        input + 1
    }
    func previous(_ input:Int)->Int {
        input - 1
    }
    return forward ? next :previous
}

forward(true)(3)
forward(false)(3)