04-函数

作者: bytebytebyte | 来源:发表于2020-10-20 21:03 被阅读0次
    //函数1-22
    //1.函数的定义,形参默认是let 也只能是let,let省略了
    func pi() -> Double {
        return 3.14
    }
    pi()
    
    func sum0(v1: Int, v2: Int) -> Int {
        return v1 + v2
    }
    print(sum0(v1:1,v2:2))
    
    //2. 3个无返回值等价 Void就是空元组
    public typealias Void = ()
    func sayHello0() -> Void {
        print("Hello0")
    }
    func sayHello1() -> () {
        print("Hello1")
    }
    func sayHello2() {
        print("Hello2")
    }
    sayHello0()
    sayHello1()
    sayHello2()
    
    //2.隐式返回:如果函数体是一个单一的表达式,那么函数会隐式返回这个表达式
    func sum1(v1: Int, v2: Int) -> Int {
        v1 + v2
    }
    print(sum1(v1: 10, v2: 20))
    
    //3.返回元组:实现多返回值
    func calculate(v1: Int, v2: Int) -> (sum2: Int, difference: Int, average: Int) {
        let sum2 = v1 + v2
        return (sum2, v1 - v2, sum2 >> 1) //结合10进制理解这个移位 2进制右移一位相当于十进制除以2
    }
    let result = calculate(v1: 20, v2: 10)
    result.sum2
    result.difference
    result.average
    
    //4.函数的文档注释
    
    ///  求和【概述】
    ///
    /// 将2个整数相加【更详细的描述】
    ///
    /// - Parameter v1:第1个参数
    /// - Parameter v2:第2个参数
    /// - Returns:2个整数的和
    ///
    /// - Note:传入2个整数即可【批注】
    ///
    func sum3(v1: Int, v2: Int) -> Int {
        v1 + v2
    }
    
    sum3(v1: 1, v2: 2)
    
    //5.参数标签
    //可以修改参数标签 time在内用 at在外用
    func goToWork(at time: String) {
        print("this time is \(time)")
    }
    goToWork(at: "08:00") //为什么这么设计?更像个句子好理解
    
    func goToWork(time: String) {
        print("this time is \(time)")
    }
    goToWork(time: "08:00")//this time is 08:00
    
    //6.可以使用下划线省略_ 省略参数标签,尽量少用,多用上边,易读
    func sum4(_ v1: Int, _ v2: Int) -> Int {
        v1 + v2
    }
    sum4(10,20)
    
    //7.默认参数值
    //参数可以有默认值
    func check(name: String = "nobbody", age: Int, job: String = "none") {
        print("name = \(name), age = \(age), job = \(job)")
    }
    check(name: "Jack", age: 20, job: "Doctor")//name = Jack, age = 20, job = Doctor
    check(name: "Rose", age: 18)//name = Rose, age = 18, job = none
    check(age: 10, job: "aaa")//name = nobbody, age = 10, job = aaa
    check(age: 15)//name = nobbody, age = 15, job = none
    //C++的默认参数值有个限制:必须从右往左设置。由于swift拥有参数标签,因此并没有此类限制,但是在省略参数标签时特别注意,避免出错
    //这里的middle参数不可省略参数标签
    func test(_ first: Int = 10, middle: Int, _ last: Int = 30) {}
    test(middle:20)
    
    
    //8.可变参数,一个函数最多只能有一个可变参数
    func sum5(_ numbers: Int...) -> Int {
        var total = 0
        for number in numbers {
            total += number
        }
        return total
    }
    sum5(10, 20, 30, 40)//100
    
    //9.Swift自带的print函数
    print("1","2","3",separator:"",terminator:"")
    print(20)//12320
    
    //10.紧跟在可变参数后面的参数不能省略参数标签 参数 string 不能省略标签,为什么?string: String如果是string: Int就分辨不清了怎么传值了
    func test0(_ numbers: Int..., string: String, _ other: String) {}
    test0(10, 20, 30, string: "Jack", "Rose")
    
    //11.输入输出参数:可以用inout定义一个输入输出参数:可以在函数内部修改外部实参的值
    //可变参数不能标记为inout,
    //inout 参数不能有默认值,
    //inout参数只能传入被多次赋值的,变量,数组元素
    var numbers0 = [10, 20, 30]
    numbers0[0] = 20
    numbers0[0] = 30
    func test1(_ num: inout Int) {
        
    }
    test1(&numbers0[0])
    print(numbers0)
    
    //12.inout参数的本质设计地址传递(引用传递)//汇编看出来的 lea是地址传递
    func swapValues0(_ v1: inout Int, _ v2: inout Int) {
        let tmp = v1
        v1 = v2
        v2 = tmp
    }
    var num1 = 10
    var num2 = 20
    swapValues0(&num1, &num2)
    
    func swapValues1(_ v1: inout Int, _ v2: inout Int) {
        (v1, v2) = (v2, v1)
    }
    
    swap(&num1, &num2)
    
    //13.修改外部变量的值
    var number0 = 10
    func add(_ num: inout Int) {
        num = 20
    }
    add(&number0)//20
    
    //14.函数重载
    //函数名相同,参数个数不同||参数类型不同||参数标签不同
    func sum6(v1: Int, v2: Int) -> Int {
        v1 + v2
    }
    //参数个数不同
    func sum6(v1: Int, v2: Int, v3: Int) -> Int {
        v1 + v2 + v3;
    }
    //参数类型不同
    func sum6(v1: Int, v2: Double) -> Double {
        Double(v1) + v2
    }
    //参数标签不同
    func sum6(_ v1: Int, _ v2: Int) -> Int {
        v1 + v2
    }
    //参数标签不同
    func sum6(a: Int, b: Int) -> Int {
        a + b
    }
    sum6(v1: 10, v2: 20)
    sum6(v1: 10, v2: 20, v3: 30)
    sum6(v1: 10, v2:20.0)
    sum6(10, 20)
    sum6(a: 10, b: 20)
    //15.函数重载注意点
    //1函数返回值类型与函数重载无关
    func sum7(v1: Int, v2: Int) -> Int { v1 + v2 }
    func sum7(v1: Int, v2: Int) {}
    //sum7(v1: 10, v2: 20)//报错
    
    //2默认参数值和函数重载一起使用产生二义性时,编译器并不会报错(在C++中会报错)
    func sum8(v1: Int, v2: Int) -> Int {
        v1 + v2
    }
    func sum8(v1: Int, v2: Int, v3: Int = 10) -> Int {
        v1 + v2 + v3
    }
    sum8(v1: 10, v2: 20)//会调用sum8(v1: Int, v2: Int)
    //3可变参数、省略参数标签、函数重载三者一起使用产生二义性时,编译器有可能会报错
    //func sum9(v1: Int, v2: Int) -> Int {
    //    v1 + v2
    //}
    //func sum9(_ v1: Int, _ v2: Int) -> Int {
    //    v1 + v2
    //}
    //func sum9 (_ numbers: Int...) -> Int {
    //    var total = 0
    //    for number in numbers {
    //        total += number
    //    }
    //    return total
    //}
    //sum9(10, 20)
    
    /*
     16.内联函数
     如果开启了编译器优化,release模式默认会开启优化,编译器会自动将某些函数变成内联函数,将函数调用展开成函数体. Build Setting -> optimization
     哪些函数不会被自动内联?
     1.函数体比较长 2.包含递归调用 3.包含动态派发
    
     
     */
    
    //理解函数内联
    func test2() {
        print()
    }
    
    test2()//函数内联后这句实际是print(),少了函数调用压栈出栈等操作直接把函数体放在了这里
    //理解动态派发
    class Person {
        func test3() {
        }
    }
    class Student: Person {
        override func test3() {
        }
    }
    class Teacher: Person {
        override func test3() {
        }
    }
    
    var p : Person = Student()
    p = Teacher()
    p.test3() //编译器无法决定调用哪个函数
    
    //在release模式下,编译器已经开启优化,会自动决定哪些函数需要内联,因此没必要使用@inline
    //永远不会被内联,即使开启了编译器优化
    @inline(never) func test4() {
        print("test4")
    }
    //开启编译器优化,即使代码很长,也会被内联(递归调用函数、动态派发的函数除外)
    @inline(__always) func test5() {
    print("test5")
    
    //17.函数类型
    //每一个函数都是有类型的,函数类型由形式参数类型、返回值类型组成
    func test4() {}// () -> Void 或者 () -> ()
    func sum10(a: Int, b: Int) -> Int { // (Int, Int) -> Int
        a + b
    }
    //18.函数类型定义变量
    var fn: (Int, Int) -> Int = sum10 //调用时不需要参数标签
    
    //19.函数类型作为函数参数
    func sum11(v1: Int, v2: Int) -> Int {
        v1 + v2
    }
    func difference0(v1: Int, v2: Int) -> Int {
        v1 - v2
    }
    func printResult(_ mathFn: (Int, Int) -> Int, _ a: Int, _ b: Int) {
        print("Result: \(mathFn(a,b))")
    }
    printResult(sum11, 5, 2) //Result: 7
    printResult(difference0, 5, 2) //Result: 3
    
    //20.高阶函数:返回值是函数类型的函数
    func next(_ input: Int) -> Int {
        input + 1
    }
    func previous(_ input: Int) -> Int {
        input - 1
    }
    func forward(_ forward: Bool) -> (Int) -> Int {//(Int) -> Int返回值类型
        forward ? next : previous
    }
    forward(true)(3) //4
    forward(false)(3) //2
    
    //21.typealias 用来给类型起别名
    typealias Byte = Int8
    //元组
    typealias Date = (year: Int, moth: Int, day: Int)
    func test5(_ date: Date) {
        print(date.0)
        print(date.year)
    }
    test5((2011, 9, 10))
    
    typealias IntFn = (Int, Int) -> Int
    func difference1(v1: Int, v2: Int) -> Int {
        v1 - v2
    }
    let fn1: IntFn = difference1
    fn1(20, 10)
    func setFn(_ fn1: IntFn) {}
    setFn(difference1)
    func getFn() -> IntFn {difference1}
    
    //22.函数嵌套:将函数定义在函数内部,不想让外部调用到
    func forward0(_ forward0: Bool) -> (Int) -> Int {
        func next(_ input: Int) -> Int {
            input + 1
        }
        func previous(_ input: Int) -> Int {
            input - 1
        }
        return forward0 ? next : previous
    }
    forward0(true)(3) //4
    forward0(false)(3) //2
    }
    

    相关文章

      网友评论

          本文标题:04-函数

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