Swift入门-简洁版(2 / 3)

440 阅读5分钟

原视频:www.bilibili.com/video/BV1uZ…

Swift入门-简洁版(1 / 3)

Swift入门-简洁版(2 / 3)

Swift入门-简洁版(3 / 3)

十四、函数

image.png

  • 形参默认是let,也只能是let

  • 无返回值:

    func sayHello() -> Void
    {
      print("Hello")
    }
    
    func sayHello() -> ()
    {
      print("Hello")
    }
    // ()是空元组
    
    func sayHello()
    {
      print("Hello")
    }
    
  • 隐式返回:

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

    func sum(v1: Int, v2: Int) -> Int 
    {
      v1 + v2
    }
    
    sum(v1: 10, v2: 20) // 30
    
  • 返回元组:实现多返回值

    func caluate(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)
    result.sum // 30
    result.difference // 10
    result.average // 15
    
  • 函数的文档注释【真的会有人写这种东西吗】

image.png

  • 注释要三个斜线

  • 概述 和 详细概述要空行

  • - Parameter v1:为要求的格式,不可少

  • - Returns:同样为格式要求

  • 空行后的- Note:为其他批注

  • 参考:swift.org/documentati…

  • 参数标签(Argument Label)

    • 可以修改参数标签

      func goToWork(at time: String)
      {
        print("this time is \(time)")
      }
      goToWork(at: "08:00")
      // this time is 08:00
      
      • time是形参
      • at是调用参数标签
      • 为了函数里外均阅读通顺
    • 可以使用下划线_来省略参数标签

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

      苹果不建议全部这么写

十五、默认参数值(Default Parameter Value)

  • 参数可以有默认值

image.png

  • C++ 的默认参数值有个限制:必须从右往左设置(←)。

    由于Swift拥有参数标签,因此并没有此类限制

  • 在省略参数标签时,需要特别注意,避免出错

image.png

十六、可变参数(Variadic Parameter)

func sum(_ numbers: Int...) -> Int
{
  var total = 0
  for number in numbers
  {
    total += number
  }
  return total
}
sum(10, 20, 30, 40) // 100
  • ...代表可变参数

  • numbers类似数组

  • 一个函数最多只能有1个可变参数

  • 紧跟在可变参数后面的参数不能省略参数标签

image.png

因为无法与可变参数的传参区分开

  • Swift自带的print函数

    public func print(_ item: Any..., separator: String = " ", terminator: String = "\n") // 可变参数、分隔符、结束符
    
    • Any代表任何类型

十七、输入输出参数(In-Out Parameter)

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

    • 函数的参数为let所以不能修函数

image.png

  • 如果想在函数内部修改外部变量:

image.png

  • 扩展:利用元组进行数值交换:

    func swapValues(_ v1: inout Int , _ v2: inout Int)
    {
      (v1,v2) = (v2,v1)
    }
    
  • 可变参数...不能标记为inout

  • inout参数不能有默认值

  • inout参数的本质是地址传递(引用传递)

  • Swift不允许你直接拿到对象地址

  • inout参数只能传入变量

十八、函数重载(Function Overload)

  • 规则

    • 函数名相同
    • 参数个数不同 || 参数类型不同 || 参数标签不同

image.png

  • 注意点

    • 返回值类型与函数重载无关

image.png

ambiguous

adj. 模棱两可的,有歧义的;不明朗的,不确定的

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

image.png

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

image.png

十九、内联函数(Inline Function)

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

image.png

  • 将函数调用展开成函数体

    func test() {
      print("123")
    }
    test()
    

    将转换为

    print("123")
    
  • 哪些函数不会内联?

  • 函数体比较长

  • 包含递归调用

  • 包含动态派发

    class Person
    {
      func test() 
      {
        
      }
    }
    
    class Student : Person
    {
      override func test() {
        
      }
    }
    
    var p: Person = Student() // 多态
    p.test()  // 动态派发
    

二十、函数类型(Function Type)

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

    func test() { } //其类型为: () -> Void 或者 () -> ()
    
    func sum (a: Int, b: Int) -> Int 
    {
      a + b
    }
    // (Int , Int) -> Int
    
    // 定义变量
    var fn:(Int , Int ) -> Int = sum
    fn:(2,3) // 5,调用时不需要参数标签(原sum调用是需要写标签的)
    
  • 函数类型作为函数参数:

    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) // Result: 7
    printResult(difference, 5, 2) // Result: 3
    
  • 函数类型作为函数返回值

    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) // 4
    forward(false)(3) // 2
    
    • 返回值是函数类型的函数,叫做高阶函数(Higher-Order Function)
  • 函数作为属性

    class Person
    {
      var age: Int
      var fn: () -> ()
    }
    
  • typealias

    • 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((2011, 9 ,10))
      
    • 按照Swift标准库的定义,Void就是空元组( )

二十一、@inline

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

二十二、嵌套函数

  • 将函数定义在函数内部

    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) // 4
    forward(false)(3) // 2
    
    • 不希望某些函数被随意调用