美文网首页
Swift5.1学习随笔之函数func

Swift5.1学习随笔之函数func

作者: SAW_ | 来源:发表于2020-04-10 17:14 被阅读0次

    Swift中的函数用func关键字定义

    func <#name#>(<#parameters#>) -> <#return type#> {
        <#function body#>
    }
    <#name#> //函数名
    (<#parameters#>) //括号里为参数(形参默认是let,也只能是let)
    <#return type#> //返回值类型
    <#function body#> //函数内部实现
    

    举个🌰

    //定义一个函数pi,无输入参数,返回值为Double类型
    func pi() -> Double {
        return 3.14159
    }
    print(pi()) // 3.14159
    //定义一个函数sum实现两数相加,需要两个Int类型参数,返回相加后的值也是Int类型
    func sum(v1: Int, v2: Int) -> Int {
        return v1 + v2
    }
    let result = sum(v1: 10, v2: 20)
    print(result) // 30
    

    无返回值的函数

    有3中表达写法

    //返回一个Void代表空,无返回值
    func func1() -> Void {
        print("func1")
    }
    //返回一个括号
    func func2() -> () {
        print("func2")
    }
    //什么都不写,连->都可以省略
    func func3() {
        print("func3")
    }
    

    隐式返回

    如果整个函数体是一个单一表达式,那么函数会隐式返回整个表达式

    //sum函数内部实现只有一句代码,既可以省略return,直接书写 v1 + v2
    func sum(v1: Int, v2: Int) -> Int {
        v1 + v2
    }
    let result = sum(v1: 10, v2: 20)
    print(result) // 30
    

    返回元组,实现多返回值

    在OC中,无法实现函数返回多个参数,只能用数组、字典等曲线实现,在swift中可以用元组实现

    func calculate(v1: Int, v2: Int) -> (sum: Int, difference: Int, average: Int) {
        let sum = v1 + v2
        return (sum, v1 - v2, sum  / 2)
    }
    let result = calculate(v1: 20, v2: 10)
    print(result.sum) // 30
    print(result.difference) // 10
    print(result.average) // 15
    

    参数标签 Argument Label

    func sum(v1: Int, v2: Int) -> Int {
        return v1 + v2
    }
    //参数名 v1 v2 就是参数标签
    

    修改参数标签,举个🌰

    func goToWork(at: String) {
        print("this time is \(at)") //这里的at 从阅读体验上来说,不太通顺
    }
    goToWork(at: "09:00")
    
    func goToWork(at time: String) {
        print("this time is \(time)") //这里内部用time,更加便于阅读理解
    }
    goToWork(at: "09:00") //外部依然显示at
    

    可以用下划线_来省略参数标签
    建议不要省略,增加阅读性

    func sum(v1: Int, v2: Int) -> Int {
        return v1 + v2
    }
    sum(v1: 10, v2: 20)
    //忽略下划线,代码更加简洁
    func sum(_ v1: Int, _ v2: Int) -> Int {
        return v1 + v2
    }
    sum(10, 20)
    

    默认参数值 Default Parameter Value

    参数可以有默认值

    //声明一个函数,需要三个参数
    //name有默认值“老王”
    //age没有默认值,必传
    //job有默认值“老司机”
    func check(name: String = "老王", age: Int, job: String = "老司机") {
        print("name = \(name), age = \(age), job = \(job)")
    }
    check(name: "张三", age: 20, job: "城管") //name = 张三, age = 20, job = 城管
    check(name: "李四", age: 19) //name = 李四, age = 19, job = 老司机
    check(age: 10, job: "小学生") //name = 老王, age = 10, job = 小学生
    check(age: 15) //name = 老王, age = 15, job = 老司机
    

    可变参数 Variadic Parameter

    Int类型后面加...表示可以传入多个参数
    这里的numbers可以理解成数组

    func sum(_ numbers: Int...) -> Int {
        var total = 0
        for number in numbers {
            total += number
        }
        return total
    }
    sum(10, 20, 30, 40) // 60
    
    func nameAll(_ names: String...) -> String {
        var result = ""
        for name in names {
            result += " \(name) "
        }
        return result
    }
    print(nameAll("1", "2", "3", "4")) //"1  2  3  4"
    

    注意:
    1、一个函数最多只能有一个可变参数
    2、紧跟在可变参数后面的参数不能省略参数标签

    输入输出参数 In-Out Parameter

    //实现传入num,是的num在函数内部+1操作
    var num = 10
    func add(_ num: Int) {
        num += 1 //此处报错 Left side of mutating operator isn't mutable: 'num' is a 'let' constant
        //因为num默认为let,不能做修改
        //并且此处num为值传递,不能修改
    }
    add(num)
    

    inout定义一个输入输出参数:可以在函数内部修改外部实参的值

    var num = 10
    func add(_ num: inout Int) {
        num += 1
    }
    add(&num) //必须加上&,地址传递
    

    举个🌰:实现连个变量的交互

    func swapValue(_ v1: inout Int, _ v2: inout Int) {
        let temp = v1
        v1 = v2
        v2 = temp
    }
    var num1 = 10
    var num2 = 20
    swap(&num1, &num2)
    
    //PS:内部实现可以用元组更方便的实现两个变量交互
    func swapValue(_ v1: inout Int, _ v2: inout Int) {
        (v1, v2) = (v2, v1)
    }
    

    注意:
    1、可变参数不能标记为inout
    2、inout参数不能有默认值
    3、inout参数的本质是地址传递(引用传递)
    4、inout参数只能传入可以被多次赋值的,比如变量等

    函数重载 Function Overload

    规则:
    1、函数名相同
    2、参数个数不同 || 参数类型不同 || 参数标签不同

    func sum(v1: Int, v2: Int) -> Int {
        v1 + v2
    }
    func sum(v1: Int, v2: Int , v3: Int) -> Int {
        v1 + v2 + v3
    } //参数个数不同
    
    func sum(v1: Int, v2: Double) -> Double {
        Double(v1) + v2
    } //参数类型不同
    func sum(v1: Double, v2: Int) -> Double {
        v1 + Double(v2)
    } //参数类型不同
    
    func sum(_ v1: Int, _ v2: Int) -> Int {
        v1 + v2
    } //参数标签不同
    func sum(a1: Int, a2: Int) -> Int {
        a1 + a2
    } //参数标签不同
    

    注意:
    1、返回值类型与函数重载无关

    func sum(v1: Int, v2: Int) -> Int { v1 + v2 }
    func sum(v1: Int, v2: Int) { }
    sum(v1: 10, v2: 20) //报错:Ambiguous use of 'sum(v1:v2:)'
    

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

    func sum(v1: Int, v2: Int) -> Int {
        v1 + v2
    }
    func sum(v1: Int, v2: Int , v3: Int = 30) -> 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) //报错:Ambiguous use of 'sum'
    
    //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) //不报错
    

    内联函数 Inline Function

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


    作用:
    1、将函数调用展开成函数体
    func test() {
        print("test")
    }
    test()
    //执行test(),会调用test函数,会开辟栈空间给函数,函数调用完会回收栈空间
    //如果调用test()能直接优化成调用print("test"),能提高性能,因为test函数内部的代码特别少,就1行
    //这就是内联函数的意思,会自动将函数调用展开成函数体代码
    


    注意:哪些函数不会内联
    1、函数体比较长
    func test1() {
        print("aaaaaaaaaaaa")
        print("bbbbbbbbbbb")
        print("dsafsdfa")
        print("aaaaaaadsfasdfaaaaa")
        print("sdfasdf")
        print("aaaaaaaasdfasdaaaaa")
        print("cxzvxcv")
    }
    test1()
    test1()
    test1()
    //这种函数就很没有意义,编译器会智能判断
    

    2、包含了递归调用

    func test2() {
        test2()
    }
    

    3、包含动态派发(OC中的动态绑定)

    class Person {
        func test() {
            
        }
    }
    class Student: Person {
        override func test() {
            
        }
    }
    class Teacher: Person {
        override func test() {
            
        }
    }
    
    var p: Person = Student() //多态
    p.test() //运行时再决定调用Person还是Student的test
    
    p = Teacher() //变量p随时可能变化
    p.test() //编译器无法确定调用谁的
    

    手动禁用内联:
    函数声明时候加上@inline(never)关键字

    //永远不会被内联,即使开启了编译器优化
    @inline(never) func test() {
        print("test")
    }
    

    手动开启内联:
    函数声明时候加上@inline(__always)关键字

    //开启编译器优化后,即使代码很长,也会被内联(递归调用函数、动态派发的函数除外)
    @inline(__always) func test() {
        print("test")
    }
    

    函数类型 Function Type

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

    func test() { }
    // test函数的类型为:() -> Void 或者 () -> ()
    
    func sum(a: Int, b: Int) -> Int {
        a + b
    } 
    // sum类型为:(Int, Int) -> Int
    

    作用:
    1、定义变量

    var fn: (Int, Int) -> Int = sum
    fn(6, 9) // 15,调用不需要参数标签
    

    2、作为函数参数

    func sum(a: Int, b: Int) -> Int {  a + b }
    func difference(a: Int, b: Int) -> Int  {  a - b }
    
    func printResult(_ mathFn: (Int, Int) -> Int, _ a: Int, _ b: Int) {
        print("Result == \(mathFn(a, b))")
    }
    
    printResult(sum, 5, 2) // 7 :调用sum函数
    printResult(difference, 5, 2) // 3 :调用difference函数
    

    3、作为函数返回值
    返回值是函数类型的函数,叫做高阶函数(Higher-Order Function)

    func next(_ input: Int) -> Int {
        input + 1
    }
    func previous(_ input: Int) -> Int {
        input - 1
    }
    //forward返回值是 (Int) -> Int函数
    func forward(_ forward: Bool) -> (Int) -> Int {
        forward ? next : previous
    }
    
    forward(true)(3) // 4 : true调用next(3)
    forward(false)(3) // 2 : false调用previous(3)
    

    嵌套函数 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)
    //外部无法直接调用next()跟previous()
    

    相关文章

      网友评论

          本文标题:Swift5.1学习随笔之函数func

          本文链接:https://www.haomeiwen.com/subject/jrormhtx.html