认识Swift系列3之函数
函数定义
func 函数名(形参...) -> 返回值 {函数体}
可以使用中文😺,表情等字符
func 函数名(形参1: String, 形参2: Int) -> 返回值类型 {
print("函数定义")
}
函数名(形参1: "参数1", 形参2: 20)
- 1.无返回值函数
func f1() -> Void { print("返回值标明为:->Void") }
func f2() -> Void { print("返回值标明为:->(),用()代替Void,Void实际上就是空元组()") }
func f3() -> Void { print("可以直接省略箭头和Void或小括号") }
f1();f2();f3()
- 2.隐式返回
func sum1(v1: Int, v2: Int) -> Int {
return v1+v2
}
func sum2(v1: Int, v2: Int) -> Int {
v1+v2
}
print("显式返回:\(sum1(v1: 1, v2: 2))")
print("隐式返回:\(sum2(v1: 1, v2: 2))")
- 3.返回多个值,可使用元组
func test_mutiple_return(v1: Int, v2: Int) -> (value1: Int, value2: Int) {
return (v2, v1)
}
let test_mutiple = test_mutiple_return(v1: 1, v2: 2);
print(test_mutiple.value1, test_mutiple.value2)
- 4.函数文档注释
/// 求和【概述】
///
/// 将2个整数相加【详细解释】
/// 传入v1和v2
///
/// - Parameter v1: 第一个参数【参数1解释】
/// - Parameter v2: 第二个参数【参数1解释】
/// - Returns: 2个参数的和【返回值解释】
///
/// - Note: 传入两个整数即可【批注】
func sum(first v1: Int, second v2: Int) ->Int {
return v1 + v2
}
sum(first: 1, second: 2)
// Note:可以在每个参数之前添加参数标签
- 5.默认参数
C++中默认参数必须从后往前设置,但是swift中没有此规定,由于swift中有标签的存在,可以用来作区分
但必须注意的是,当省略了参数标签时,可能出错
注意,当所有参数都使用参数标签时,其实应遵循从右往左的原则,避免歧义
func test(_ v1: Int = 10, v2: Int, _ v3: Int = 30) { print(v1, v2, v3) }
test(v2: 2)
- 6.可变参数
// 一个函数最懂支持一个可变参数
func sum_variadic(_ numbers: Int...){}
sum_variadic(1, 2, 3, 4, 5)
// 紧跟在可变参数之后的参数不能省略标签,否则出现歧义
func test_variadic(_ numbers: Int..., string: String, _ other: String){}
test_variadic(1, 2, 3, string: "name", "jack")
- 7.swift自带的print函数
// public func print(_ items: Any..., separator: String = " ", terminator: String = "\n")
print(1, 2, 3, 4, separator: " <分隔符> ", terminator: "这是结尾,通常是换行\n")
- 8.输入输出参数 In-Out parameter
inout 本质上是引用传递,不过在不同的条件下表现不同
1.本质引用传递
2.特殊情况
1)当传入的a、b为某个对象o的计算属性p(包含getter setter方法时) 先调用p的getter方法,将或的值存储在一个临时空间,这里暂记为tmp将tmp的地址传入inout参数的方法内,inout参数的方法处理完成后调用p的setter方法,完成p的计算方法执行
2)当传入的a、b为某个对象o的存储属性p(但是该属性添加了属性观察器 willSet didSet,类似OC的KVO)inout表现和1)相同
综上:inout本质为引用传递(地址传递),只不过涉及到对象的计算属性和添加了属性观察期的存储属性时为了让属性对应的方法能够被调用到,会新增一个临时空间来做中专,并调用和属性相关的方法
func swap(a: inout Int, b: inout Int) {
let tmp = a
a = b
b = tmp
}
var a = 10;
var b = 20;
print("a = \(a), b = \(b)")
swap(a: &a, b: &b)
print("a1 = \(a), b1 = \(b)")
- 9.函数重载
返回值不构成重载:由于返回值不构成重载,这里不考虑此种情况
//
// 条件:参数个数、参数标签、参数类型
func sum(v1: Int, v2: Int) {}
func sum(v1: Int, v2: Int, v3: Int) {} // 参数个数
func sum(_ v1: Int, v2: Int) {} // 参数标签
func sum(s1: Int, s2: Int) {} // 参数标签
// func sum(v1: Int, v2: Double) {} // 参数类型
// 注意:默认参数和重载一起使用时,可能阐述二义性
func sum1(v1: Int, v2: Int) { print("==\(#function)") }
func sum1(v1: Int, v2: Int, v3: Int = 10) { print("==\(#function)") }
sum1(v1: 1, v2: 2) // 调用 sum1(v1: Int, v2: Int)
- 10.内联函数
Note:如果编译器开启了编译优化(Release模式自动开启),编译器会自动将某些函数变成内联
也可手动设置:Build Settings->搜索Optimization Level—>Debug->Optimize for Speed[-O]
通常情况下并不需要我们手动声明内联
- 如果不想被内联'@inline(never)',即使编译器开启优化也不会被内联
- 如果想被内联'@inline(__always)',即使代码很长也会被内联,除非是递归、动态派发的函数
// 部分函数不会被自动内联(内联是编译期特性)
// 1.函数体过长(防止栈空间溢出)
// 2.递归函数(递归的循环调用特性决定了不能内联)
// 3.动态派发函数(需要在运行时才能获取到相关信息函数,编译期无法内联)
@inline(never) func test1() {}
@inline(__always) func test2() {}
- 11.函数类型 Function Type
在swift中,函数也是一种类型,函数类型由形参、返回值类型组成
// 类型1 ()->Void / ()->()
func test1(){}
// 类型2 (Int, Int)->Int
func test2(v1: Int, v2: Int)->Int { print("调用test2"); return 10 }
// 定义量变量
let fn: (Int, Int)->Int = test2
fn(2, 3)
// 函数类型作为参数
func sum(v1: Int, v2: Int)->Int {return v1+v2 }
func printResult(_ addFn: (Int, Int)->Int, v1: Int, v2: Int) {
print("\(v1) + \(v2) = \(addFn(v1, v2))")
}
printResult(sum, v1: 10, v2: 20)
// 函数类型作为参数
func test3()->(Int, Int)->Int {
func sum_test(v1: Int, v2: Int)->Int {
print("函数类型作为参数")
return v1+v2
}
return sum_test
}
let fn1 = test3()
fn1(1, 2)
- 12.typealias给函数起别名
// 类似typealias,定义类名别
typealias NSInteger = Int64
typealias BOOL = Bool
// 定义元组名别
typealias Date = (year: Int, month: Int, day: Int)
func test1(date: Date){}
test1(date: (year: 2019, month: 7, day: 10))
// 给函数定义别名
typealias AddFn = (Int, Int)->Int
func add(v1: Int, v2: Int)->Int { return v1+v2}
func test2(fn: AddFn){}
test2(fn: add)
- 13.内嵌函数,swift中函数可以嵌套
嵌套不会改变函数的本质,本质上函数还是存储在数据段,只是作用于发生改变而已
func test_func_contains(){
print("内嵌函数0")
func test1(){
print("内嵌函数1")
func test2(){
print("内嵌函数2")
func test3(){ print("内嵌函数3") }
test3()
}
test2()
}
test1()
}
test_func_contains()