函数在任何语言中都是存在的,Swift中函数更加灵活。

一、函数的定义

1.1. 有返回值(形参默认是let,也只能是let)

func pi() -> Double {
return 3.14
}
print(pi()) // 输出:3.14 func sum(v1: Int, v2: Int) -> Int {
return v1 + v2
}
print(sum(v1: 10, v2: 20)) // 输出:30

1.2. 无返回值

func hello() -> Void {
print("hello")
} func hello() -> () {
print("hello")
} func hello() {
print("hello")
}
hello() // 输出:hello

1.3. 如果整个函数体是一个单一表达式,那么函数会隐式返回这个表达式

func sum(v1: Int, v2: Int) -> Int {
v1 + v2
} print(sum(v1: 10, v2: 10)) // 输出:20

1.4. 返回元组:实现多返回值

func calculate(v1: Int, v2: Int) -> (sum: Int, difference: Int, average: Int) {
let sum = v1 + v2
return (sum, v1 - v2, sum >> 1)
}
let result = calculate(v1: 10, v2: 20)
print(result.sum, result.difference, result.average) // 输出:30 -10 15

1.5. 参数标签

函数可以修改参数标签:

// at是外面调用的,time是函数内部使用的
func goToWord(at time: String) {
print("time is \(time)")
}
goToWord(at: "8:00")

可以使用下划线_省略参数标签:

func sum(_ v1: Int, _ v2: Int) -> Int { v1 + v2}

sum(10, 20)

1.6. 默认参数值

  • 参数可以有默认值
func check(name: String = "nobody", age: Int, job: String = "none") {
print("name=\(name), age=\(age), job=\(job)")
}
check(age: 10)
check(name: "Jack", age: 20, job: "Programmer")
check(name: "Eve", age: 18)
check(age: 10, job: "Superman")
/*
输出:
name=nobody, age=10, job=none
name=Jack, age=20, job=Programmer
name=Eve, age=18, job=none
name=nobody, age=10, job=Superman
*/
  • C++的默认参数有个限制:必须从右往左设置,而且不能跨标签;Swift拥有参数标签,因此没有此类限制
  • 省略参数标签时,需要特别注意,避免出错
  • 没有默认值的参数标签不能省略(如上面代码age就不能省略)

1.7. 可变参数

  • 一个函数最多只能有1个可变参数
func sum(_ numbers: Int...) -> Int {
var total = 0
for number in numbers {
total += number
}
return total
}
let result = sum(10, 20, 30, 40)
print(result) // 输出:100
  • 紧跟在可变参数后面的参数不能省略参数标签(思考:如果省略了会怎么样?)
func test(_ numbers: Int..., string: String, _ other: String) {

}
test(10, 20, 30, string: "idbeny", "1024星球")

1.8. 输入输出参数

  • 可以用inout定义一个输入输出参数:可以在函数内部修改外部实参的值
  • inout必须和&配合使用
  • 本质上是地址传递
  • 可变参数不能标记为inout
  • inout参数不能有默认值
  • inout参数只能传入可以被多次赋值的

如下修改会报错(因为形参是用let修饰的)

使用inout&

var number = 10
func add(_ num: inout Int) {
num = 20
}
add(&number)
print(number) // 输出:20

通过这种方式也可以交换两个变量的值(其实官方有提供交换函数swap

// 方法一(使用临时变量)
func swapValues(_ v1: inout Int, _ v2: inout Int) {
let temp = v1
v1 = v2
v2 = temp
}
var num1 = 10
var num2 = 20
swapValues(&num1, &num2)
print("num1=\(num1), num2=\(num2)") // 输出:num1=20, num2=10 // 方法二(使用元组)
var num3 = 30
var num4 = 40
func swapValues1(_ v1: inout Int, _ v2: inout Int) {
(v1, v2) = (v2, v1)
}
swap(&num3, &num4)
print("num3=\(num3), num4=\(num4)") // 输出:num3=40, num4=30 // 方法三(系统提供的swap函数)
var num5 = 50
var num6 = 60
swap(&num5, &num6)
print("num5=\(num5), num6=\(num6)") // 输出:num5=60, num6=50

二、函数的文档注释

官网介绍:https://swift.org/documentatior/api-design-guidelines

光标放到对应函数名称上,按下Option即可查看函数相关描述文档

  • 上图看到sum的函数描述都是空的,如何填写描述信息呢?
  • 添加文档快捷键(光标一定要在函数上或函数上方):Command + Option + /

默认的文档注释

/// <#Description#>
/// - Parameters:
/// - v1: <#v1 description#>
/// - v2: <#v2 description#>
/// - Returns: <#description#>
func sum(v1: Int, v2: Int) -> Int { v1 + v2}

更详细的文档注释(概述和详述一定要隔开,否则会默认为详述)

/// 将2个整数相加【概述】
///
/// 将2个整数相加【详细的描述】
/// - Parameters:
/// - v1: 第一个参数
/// - v2: 第二个参数
/// - Returns: 2个参数的和
/// - Note:传入2个整数【批注】
func sum(v1: Int, v2: Int) -> Int { v1 + v2}

效果

三、函数重载

  • OC是不支持函数重载的,但Swift支持函数重载
  • 规则
    • 函数名相同
    • 参数个数不同 || 参数类型不同 || 参数标签不同

以下函数都构成了函数重载,都是可以正常调用的,且函数没有冲突:

// 参照
func sum(v1: Int, v2: Int) {
v1 + v2
} // 参数个数不同
func sum(v1: Int, v2: Int, v3: Int) {
v1 + v2 + v3
} // 参数类型不同
func sum(v1: Int, v2: Double) {
Double(v1) + v2
} // 参数标签不同(忽略标签)
func sum(_ v1: Int, _ v2: Int) {
v1 + v2
} // 参数标签不同(标签名不同)
func sum(a: Int, b: Int) {
a + b
}
  • 返回值类型与函数重载无关

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

func sum(v1: Int, v2: Int) -> Int {
v1 + v2
} func sum(v1: Int, v2: Int, v3: Int = 30) -> Int {
v1 + v2 + v3
} sum(v1: 10, v2: 20) // 输出:30
  • 可变参数、省略参数标签,函数重载一起使用产生二义性时,编译器有可能会报错

为什么是可能会报错?(下面代码可以正常执行,所以平时开发中也不建议这样写)

func sum(_ v1: Int, _ v2: Int) -> Int {
v1 + v2
} func sum(_ numbers: Int...) -> Int {
var total = 0
for num in numbers {
total += num
}
return total
} sum(10, 20) // 输出:30

四、函数类型

每一个函数都是有类型的,函数类型由形式参数类型,返回值类型组成:

  • 函数类型可以作为函数参数传递;
  • 函数类型可以作为函数返回值;
  • 返回值是函数类型的函数,叫做高阶函数

五、嵌套函数

将函数定义在函数内部:

func foward(_ forward: Bool) -> (Int) -> Int {
func next(_ input: Int) -> Int {
input + 1
}
func previous(_ input: Int) -> Int {
input - 1
}
return forward ? next : previous
}
foward(true)(1) // 输出:2
foward(false)(2) // 输出:1

六、内联函数

如果开启了编译器优化(Release模式默认开启),编译器会自动将某些函数变成内联函数:

  • Release默认按照快速运行方式优化;
  • Debug也可以手动开启,但是为了开发中方便调试,一般都会关闭。

内联函数的作用?

  • 内联函数在C++中的经常出现,如果某一个函数是内联函数,编译器在编译的时候会把适当的代码块中的代码放到对应位置,提高代码执行的效率
  • 将函数调用展开成函数体
func test() {
print("test")
}
test()
  • 以上代码如果开启编译器优化,test()会替换为print("test")

不是所有的内联函数都会被编译器展开函数体,那些函数不会被内联?

  • 函数体比较长
  • 包含递归调用
  • 包含动态派发

@inline

永远不会被内联(即使开启了编译器优化)

@inline(never) func test() {
print("test")
}

开启编译器优化后,及时代码很长,也会被内联(递归调用、动态派发的函数除外):

@inline(__always) func test1() {
print("test")
}
  • 在Release模式下,编译器已经开启优化,会自动决定哪些函数需要内联,因此没必要使用@inline

更多系列文章,请关注 微信公众号【1024星球】

Swift系列三 - 函数的更多相关文章

  1. Swift(三.函数)

    一.swift中的函数分为以下几类吧 1>无参无返   2>无参有返 3>有参无返  4>有参有返  5>有参多返 二.看下面几个例子吧 1>无参无返 func a ...

  2. Swift语法基础入门三(函数, 闭包)

    Swift语法基础入门三(函数, 闭包) 函数: 函数是用来完成特定任务的独立的代码块.你给一个函数起一个合适的名字,用来标识函数做什么,并且当函数需要执行的时候,这个名字会被用于“调用”函数 格式: ...

  3. 窥探Swift系列博客说明及其Swift版本间更新

    Swift到目前为止仍在更新,每次更新都会推陈出新,一些Swift旧版本中的东西在新Swift中并不适用,而且新版本的Swift会添加新的功能.到目前为止,Swift为2.1版本.去年翻译的Swift ...

  4. swift入门篇-函数

    今天给大家介绍 swift函数,swift函数和c#,js的写法大致一直,但是与object-c写法有很大不同点.废话不多说,直接开始了. 1:函数  --常量参数 func 函数名( 参数变量:类型 ...

  5. 前端构建大法 Gulp 系列 (三):gulp的4个API 让你成为gulp专家

    系列目录 前端构建大法 Gulp 系列 (一):为什么需要前端构建 前端构建大法 Gulp 系列 (二):为什么选择gulp 前端构建大法 Gulp 系列 (三):gulp的4个API 让你成为gul ...

  6. [Swift系列]003- 函数

    [基础] Swift函数格式: 1.定义格式: func   函数名(参数名1:数据类型,... ,参数名n:数据类型) -> (返回值类型1,...,返回值类型n){ ///函数体内语句 } ...

  7. 李洪强iOS开发Swift篇—08_函数(2)

    李洪强iOS开发Swift篇—08_函数(2) 一.函数类型 函数类型也是数据类型的一种,它由形参类型和返回值类型组成,格式是 (形参类型列表) -> 返回值类型 1 func sum(num1 ...

  8. 李洪强iOS开发Swift篇—07_函数

    李洪强iOS开发Swift篇—07_函数 一.函数的定义 (1)函数的定义格式 1 func 函数名(形参列表) -> 返回值类型 { 2 // 函数体... 3 4 } (2)形参列表的格式 ...

  9. Swift学习笔记 - 函数与闭包

    import Foundation //1.函数的定义与调用//以 func 作为前缀,返回箭头 -> 表示函数的返回类型func sayHello(name: String) -> St ...

随机推荐

  1. 1.5 PHP基础+1.5.1 访问数据库

    PHP作为流行的网站开发语言,具有上手简单,运行速度快的特点,它和javascript类似,无需定义变量类型,免去了使用者要对变量类型转换的烦恼,当然了,这就要求我们要对变量类型隐式转换过程予以关注. ...

  2. 杨辉三角的实现(Java)

    杨辉三角的实现 一.什么是杨辉三角 杨辉三角是二项式系数在三角形中的一种几何排列.每个数等于它上方两数之和.每行数字左右对称,由1开始逐渐变大.第n行的数字有n项.前n行共[(1+n)n]/2 个数. ...

  3. Java字符串==和equals的区别

    首先我们来了解一下String类,Java的字符串是一旦被赋值之后无法更改的(这里的无法更改是指不能将字符串中单个或一段字符重新赋值),这也是Java虚拟机为了减少内存开销,避免字符串的重复创建设立的 ...

  4. 【框架】SPI四种模式+通用设备驱动实现-源码

    目录 前言 bsp_spi.c bsp_spi.h bsp_flash.c bsp_flash.h 前言 SPI 介绍为搜集百度资料+个人理解 其余为原创(有误请指正) 集四种模式于一身 demo 采 ...

  5. 未来直播 “神器”,像素级视频分割是如何实现的 | CVPR 冠军技术解读

    被誉为计算机视觉领域 "奥斯卡" 的 CVPR 刚刚落下帷幕,2021 年首届 "新内容 新交互" 全球视频云创新挑战赛正火热进行中,这两场大赛都不约而同地将关 ...

  6. Clang Static Analyzer-使用手册-编写Checker框架

    Clang Static Analyzer-使用手册-编写Checker Checker是这个工具的灵魂 有了checker才可以检查你的代码 相当于就是CSA通过checker定义的检查方法去检查代 ...

  7. 案例分析作业——VS和VS Code

    项目 内容 这个作业属于哪个课程 2021春季软件工程(罗杰 任健) 这个作业的要求在哪里 案例分析作业 我在这个课程的目标是 认真完成课程要求并提高相应能力 这个作业在哪个具体方面帮助我实现目标 学 ...

  8. Web协议详解与抓包实战,高效解决网络难题

    无论你是前后端工程师,还是运维测试,如果想面试更高的职位,或者要站在更高的角度去理解技术业务架构,并能在问题出现时快速.高效地解决问题,Web 协议一定是你绕不过去的一道坎. 旨在帮助你对各种常用 W ...

  9. JavaCV 视频滤镜(LOGO、滚动字幕、画中画、NxN宫格)

    其实,在JavaCV中除了FFmpegFrameGrabber和FFmpegFrameRecorder之外,还有一个重要的类,那就是FFmpegFrameFilter. FFmpegFrameFilt ...

  10. HUAWEI AppGallery Connect翻译服务升级,方便应用出海本地化

    HUAWEI AppGallery Connect翻译服务全新升级,携手新宇智慧.语言桥等多家服务商为全球开发者提供优质的翻译服务,解决应用在全球分发时面临的多语言本地化问题,通过平台化与全环节的翻译 ...