Swift学习(四):函数(定义,隐式返回,多返回值,参数标签,默认参数值,可变参数,inout输入输出参数,函数重载,内联函数,嵌套函数,typeslias)

函数的定义

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这种字面量)
  • 特别注意,大部分是引用传递,但是当传递给inout参数的是计算属性,有监听器的属性等内容,其本质并非引用传递

-------------------------------------------------------------------------------------------------------------------------------

函数重载

  • 规则:
  1. 函数名相同
  2. 参数个数不同 || 参数类型不同 || 参数标签不同

和第一个相比参数个数不同

和第一个相比参数类型不同

和第一个相比参数标签不同

相应的输出结果:

-------------------------------------------------------------------------------------------------------------------------------

函数重载注意点

  • 返回值类型与函数重载无关,即使不一样也会报错

 编译器分不清该用哪个

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

 默认使用第一个sum函数

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

-------------------------------------------------------------------------------------------------------------------------------

内联函数(Inline Function)

  • 如果开启了编译器优化(Release模式默认会开启优化,Debug模式默认不开启,需要手动调整),编译器会自动将某些函数变为内联函数。
  • 将函数调用展开成函数体(比如将function test {print("A")} 直接转化成print("A"),消除了函数体的调用,节省了内存开销)

  • 哪些函数不会被内联
  1. 函数体比较长
  2. 包含递归调用
  3. 包含动态派发
  • @inline

在Release模式下,编译器已经开启优化,会自动决定哪些函数需要内联 ,因此没必要使用@inline

-------------------------------------------------------------------------------------------------------------------------------

函数类型(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)

  • 将函数定义在函数内部

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章