返回值
有返回的函数
-
返回字符串
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