Swift-函数

返回值

有返回的函数

  • 返回字符串

    func sitename() -> String {
        return "swift学习笔记"
    }
    print(sitename()) // 打印 swift学习笔记
    复制代码

无返回值的函数

  • void 为一个空元组
  • 三种情况:void , 空元祖,不写返回
    func sayHello() -> Void {
        print("Hello")
    }
    
    //返回值类型用空元祖 () 代替
    func sayBayBay() -> () {
        print("BayBay")
    }
    
    func sayThanks(){
        print("Thanks")
    }
    复制代码

函数的隐式返回

  • 不写return

    
    //函数体是一个表达式 a1 + a2,没有写 return
    func sum(a1: Int, a2: Int) -> Int {
        a1 + a2
    }
    sum(a1: 10, a2: 20) // 30
    复制代码

元组作为函数返回值

  • 返回元组

    func calculate(num1: Int, num2: Int) -> (sum: Int, difference: Int) {
        let sum = num1 + num2
        let difference = num1 - num2
        return (sum, difference)
    }
    let result = calculate(num1: 30, num2: 10)
    print(result.sum) // 打印 40
    print(result.difference) // 打印 20
    复制代码
  • 可选元组作为返回值

func fun6 (array: [Int]) -> (min: Int, max: Int)? {
 // 安全处理
 if array.isEmpty { return nil }
 var currentMin = array[0]
 var currentMax = array[0]
 for value in array {
   if value < currentMin {
     currentMin = value
   }
   if value > currentMax {
     currentMax = value
   }
 }
 return (currentMin, currentMax)
}
let result = fun6(array: [8, -6, 2, 109, 3, 71])

复制代码

参数

局部参数名

  • 函数的实现内部使用
func sample(number: Int) {
   println(number)
}
sample(number: 1) 
sample(number: 2)
sample(number: 3)
复制代码

外部参数名(参数标签)

  • 用于在函数调用时传递给函数的参数
func goToWork(at time: String) {
    print("work time is \(time)")
}
goToWork(at: "9:00")
复制代码
  • 不写at,time即作为参数标签,又作为参数名称

使用_来省略函数的参数标签

func sum(_ a1: Int, _ a2: Int) -> Int {
    a1 + a2
}
sum(10, 20)
复制代码

默认参数值

func check(name: String = "nobody", age: Int, job: String = "none") {
    print("name is \(name), age is \(age), job is \(job)")
}
check(name: "Mars", age: 18, job: "student")
check(name: "Tom", age: 20)
check(age: 20, job: "teacher")
check(age: 10)
复制代码

可变参数

  • 一个函数只能有1个可变参数
  • 紧跟在可变参数后面的参数不能省略参数标签
func sum2(numbers: Int...) -> Int {
    var result = 0
    for number in numbers {
        result += number
    }
    return result
}
sum2(numbers: 10, 20, 30, 40) // 100
复制代码
func test(_ numbers: Int..., str: String, _ other: String) {}
test(10, 20, 30, str: "Mars", "Hello")
复制代码

输入输出参数

  • swift中函数的参数默认是 let 类型,常量进行加 1 操作,程序会报错
  • 参数是值传递,无法修改变量 number 的值
var number = 10
func add(_ num: Int) {
    num += 1 //error
}
add(2)
复制代码
  • inout 地址传递
  • 这样函数内部,可以修改外部变量 number的值
var number = 10
func add(_ num: inout Int) {
    num += 1
}
add(&number) // 11
复制代码

交换两个变量值的函数

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) // 打印输出20
print(num2) // 打印输出10
复制代码
  • 利用元组简化交换过程
func swapValue(_ v1: inout Int, _ v2: inout Int) {
    (v1, v2) = (v2 ,v1)
}
复制代码
  • Swift中已经提供了 swap(a: &T, b: &T) 交换两个变量的值

函数类型

  • 由函数的参数类型返回类型组成。函数类型不带参数标签
func addTwoInts(_ a: Int, _ b: Int) -> Int {
    return a + b
}
func printHelloWorld() {
    print("hello, world")
}

//函数类型分别为:(Int, Int) -> Int和() -> Void。
复制代码
  • 常量或变量定义为函数类型
  • 函数类型作为参数类型
  • 函数类型作为返回类型
static func functionTypesTest() {
        print("\n-----------------函数:函数类型测试----------------")
        func addTwoInts(_ a: Int, _ b: Int) -> Int { return a + b }
        func multiplyTwoInts(_ a: Int, _ b: Int) -> Int { return a * b }
        // 上面两个函数的函数类型都是 (Int, Int) -> Int, 即输入两个 Int 类型数据,返回一个 Int 类型数据
        
        // 如果一个函数没有返回值,则返回值默认是 Void 类型(上面函数定义有详细讲解),因此下面函数的函数类型是 () -> Void
        func printHelloWorld() { print("hello, world") }
        
        // 函数类型可以当作普通类型一样使用
        var mathFunction: (Int, Int) -> Int = addTwoInts(_:_:) // 也可以直接写成 addTwoInts,省略后面的 (_:_:)
        print("addTwoInts:", mathFunction(10, 10))
        mathFunction = multiplyTwoInts // 重新赋值,现在 mathFunction 引用 multiplyTwoInts 函数
        print("multiplyTwoInts:", mathFunction(10, 10))
        let mathFunctionAnother = addTwoInts // 使用类型推断,推断出 mathFunctionAnother 常量的类型为 (Int, Int) -> Int
        print("addTwoInts mathFunctionAnother:", mathFunctionAnother(100, 100))
        
        // 函数类型可以作为函数的参数,函数类型也可以被标记为 inout 参数
        func printMathResult(_ mathFunc: (Int, Int) -> Int, _ a: Int, _ b: Int) {
            print("函数类型作为参数", mathFunc(a, b))
        }
        printMathResult(addTwoInts(_:_:), 10, 10)
        printMathResult(multiplyTwoInts, 10, 10)
        
        // 函数类型作为返回值
        func stepForward(_ input: Int) -> Int { return input + 1 }
        func stepBackward(_ input: Int) -> Int { return input - 1 }
        func chooseStepFunction(backward: Bool) -> (Int) -> Int {
            return backward ? stepBackward : stepForward
        }
        print("chooseStepFunction:", chooseStepFunction(backward: true)(10))
        print("chooseStepFunction:", chooseStepFunction(backward: false)(10))
    }
复制代码

重载函数

  • 用来实现功能类似而所处理的数据类型不同的问题
  • 函数名相同
  • 参数个数不同 || 参数类型不同 || 参数标签不同
  • 编译器并不会报错,调用方法也会执行对应的方法
// 参数个数不同
func sum(a1: Int, a2: Int) -> Int {
    a1 + a2
}
func sum(a1: Int, a2: Int, a3: Int) -> Int {
    a1 + a2
}

// 参数类型不同
func sum(a1: Int, a2: Double) -> Double {
    Double(a1) + a2
}
func sum(a1: Double, a2: Int) -> Double {
    a1 + Double(a2)
}

// 参数标签不同
func sum(_ a1: Int, _ a2: Int) -> Int {
    a1 + a2
}
func sum(a: Int, b: Int) -> Int {
    a + b
}
复制代码
  • **报错情况**
// 返回值类型不同
func sum(a1: Int, a2: Int) -> Int {
    a1 + a2
}
func sum(a1: Int, a2: Int) {
    a1 + a2
}
复制代码
  • 有个默认参数,编译器不会报错,有歧义,会执行第一个函数
func sum(a1: Int, a2: Int) -> Int {
    a1 + a2
}
func sum(a1: Int, a2: Int, a3: Int = 10) -> Int {
    a1 + a2 + a3
}

sum(a1: 10, a2: 20)
复制代码

嵌套函数

  • 嵌套函数外界不可见,但可以被直接外围函数调用
  • public 等访问控制不能用在嵌套函数中
static func nestedFunctions() {
        
        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
        }
        print("Nested Functions chooseStepFunction:", chooseStepFunction(backward: true)(10))
        print("Nested Functions chooseStepFunction:", chooseStepFunction(backward: false)(10))
        
        func nested1() {
            func nested2() {
                func nested3() {
                    // public func nested4() { } // 编译报错,public 等访问控制不可以用在嵌套函数中
                }
            }
            nested2()
            // nested3()  编译报错,对 nested1 不可见,嵌套函数只能被直接外围函数可见。
        }
    }
复制代码

派发机制

直接派发 Direct Dispatch (静态派发)

  • CPU直接按照函数地址调用,速度最快
  • 静态派发同时支持 值类型 和 引用类型
  • 直接派发的缺点:没有动态性,不支持继承

函数表派发 Table Dispatch (动态派发)

  • 函数表存取了每个函数实现的指针
class ParentClass {
    func method1() {}
    func method2() {}
}
class ChildClass: ParentClass {
    override func method2() {}
    func method3() {}
}

let obj = ChildClass()
obj.method2()
复制代码

  • 调用method2() 过程
读取该对象(0XB00)的vtable.
读取method2函数指针0x222.
跳转到地址0X222,读取函数实现.
复制代码

消息机制派发 (Message Dispatch)(动态派发)

  • 动态派发仅支持 引用类型, 比如 Class ,因为class有继承特性
id returnValue = objc_msgSend(someObject, @selector(messageName:), parameter);

复制代码

Swift如何派发函数

  • 值类型stuct中函数,使用直接派发(因为他们没有继承体系)
  • class对象使用函数表派发

  • final: 函数无法被重写,使用直接派发 不会在vtable中出现
  • dynamic: 值类型和引用类型的函数均可添加dynamic关键字
  • @objc: 可以将Swift函数暴露给Objc运行时,变成函数表派发
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享