Swift学习(四):函数
函数的定义
func: 声明这是一个函数
sum:函数名
(v1: Int, v2: Int): v1,v2是参数名, Int是参数类型
-> Int:返回值为Int
sum(v1: 10, v2: 20):调用函数,调用函数时有参数名(v1, v2)必须带着
形参默认是let,也只能是let
- 无返回值的函数
->()表示返回值为空,()实际上是一个空元组
-------------------------------------------------------------------------------------------------------------------------------
隐式返回
如果整个函数体是一个单一表达式,那么函数会隐式返回这个表达式
-------------------------------------------------------------------------------------------------------------------------------
返回元组:实现多返回值
-------------------------------------------------------------------------------------------------------------------------------
函数的文档注释
参考:https://swift.org/documentation/api-design-guidelines/
-------------------------------------------------------------------------------------------------------------------------------
参数标签(Argument Label)
- 可以修改参数标签
- 可以使用下划线加空格_ 省略参数标签
-------------------------------------------------------------------------------------------------------------------------------
默认参数值(Deafault Parater Value)
- 参数可以有默认值
- C++的默认参数有个限制:必须从右往左设置。由于Swift拥有参数标签,所以并没有此类限制
- 但是在省略参数标签时需要特别注意:要传入的没有默认值的参数必须要设置参数标签
-------------------------------------------------------------------------------------------------------------------------------
可变参数(Variadic Parameter)
Int...:表示一个或多个类型为Int的参数
一个参数最多只能有一个可变参数
紧跟在可变参数后面的参数不能省略参数标签,否则会认为是可变参数中的其中一个参数
-------------------------------------------------------------------------------------------------------------------------------
Swift自带的print函数
-------------------------------------------------------------------------------------------------------------------------------
输入输出参数(In-Out Parameters)
注意:Swift屏蔽掉了一些东西,不能直接输出地址,会报错
Xcode进入汇编模式: DeBug --> Debug Workflow --> Always Show Disassembly
下图:callq(表示这是一个函数方法) 0x100000f60表示函数地址
lea:汇编里的地址传递指令, 表示把0x10da加rip表示的地址传递给rdi,用%开头的表示寄存器,也就是说rdi里存的是地址值
(%rdi)表示根据rdi存储的地址值找到相应的存储空间
mov指令是赋值指令。
普通参数传递和inout参数地址传递汇编代码对比:
/*
这是普通参数传递,明显有mov赋值指令
var number = 10
func test(_ num: Int) {
}
test(number)
0x100000f5e <+78>: movq -0x30(%rbp), %rdi
0x100000f62 <+82>: callq 0x100000f70 ; TestSwift.test(Swift.Int) -> () at main.swift:24
这是inout输入输出参数,没有mov赋值指令,有lea地址指令
var number = 10
func test(_ num: inout Int) {
}
test(&number)
0x100000f47 <+55>: leaq 0x10ca(%rip), %rdi ; TestSwift.number : Swift.Int
0x100000f4e <+62>: callq 0x100000f70 ; TestSwift.test(inout Swift.Int) -> () at main.swift:24
*/
这里说汇编是因为要论证函数的输入输出参数(inout)是地址传递,并不是网上其他人说的先把参数传给一个中间值,然后把中间值当作返回值返回,然后赋值给外部参数,这里涉及到汇编就不多说了。
- 可以用inout定义一个输入输出参数:可以在函数内部修改外部实参的值,比如交换两个数的值
也可以用元组
- 可变参数不能标记为inout
- inout参数不能有默认值
- inout参数的本质是地址传递(引用传递)
- inout参数只能传入可以被多次赋值的(也就是需要用var,不能用let,更不能用40这种字面量)
-------------------------------------------------------------------------------------------------------------------------------
函数重载
- 规则:
- 函数名相同
- 参数个数不同 || 参数类型不同 || 参数标签不同
和第一个相比参数个数不同
和第一个相比参数类型不同
和第一个相比参数标签不同
相应的输出结果:
-------------------------------------------------------------------------------------------------------------------------------
函数重载注意点
- 返回值类型与函数重载无关,即使不一样也会报错
编译器分不清该用哪个
- 默认参数值和函数重载一起使用产生二义性,但是编译器不会报错(在C++中会报错)
默认使用第一个sum函数
- 可变参数、省略参数标签、函数重载一起使用产生二义性时,编译器有可能会报错
-------------------------------------------------------------------------------------------------------------------------------
内联函数(Inline Function)
- 如果开启了编译器优化(Release模式默认会开启优化,Debug模式默认不开启,需要手动调整),编译器会自动将某些函数变为内联函数。
- 将函数调用展开成函数体(比如将function test {print("A")} 直接转化成print("A"),消除了函数体的调用,节省了内存开销)
- 哪些函数不会被内联
- 函数体比较长
- 包含递归调用
- 包含动态派发
-------------------------------------------------------------------------------------------------------------------------------
函数类型(Function Type)
- 每个函数都是有类型的,函数类型由形式参数类型、返回值类型组成
函数类型为: () -> Void 或 () -> ()
函数类型为: (Int, Int) -> Int
通过函数类型定义变量,调用时不需要参数标签
- 函数类型作为函数参数
- 函数类型作为函数返回值
其中forward(_ forward: Bool) -> (Int) ->Int 表示forward(_ forward: Bool)这个函数的返回值是一个函数类型,即(Int) ->Int,它表示一个参数为Int,返回值也是Int类型的函数
返回值是函数类型的函数,叫做高阶函数。
-------------------------------------------------------------------------------------------------------------------------------
typealias
- typealias用来给类型起别名
typealias给元组起别名
typealias给函数类型起别名IntFn,将IntFn作为参数类型和返回值类型
-------------------------------------------------------------------------------------------------------------------------------
嵌套函数(Nested Function)
- 将函数定义在函数内部
上一篇: Maven面试必备
推荐阅读
-
C#使用round函数四舍五入的方法
-
sql cast,convert,QUOTENAME,exec 函数学习记录
-
Swift中的协议(protocol)学习教程
-
PHP 面向对象程序设计(oop)学习笔记 (四) - 异常处理类Exception
-
Python中集合的内建函数和内建方法学习教程
-
Sql学习第四天——SQL 关于with cube,with rollup和grouping解释及演示
-
Python学习笔记之自定义函数用法详解
-
SQL学习笔记七函数 数字,日期,类型转换,空值处理,case
-
python学习笔记之调用eval函数出现invalid syntax错误问题
-
javascript函数的四种调用模式