【学习】重学Swift5-函数和闭包
五、函数和闭包
函数
常见形式
// 无形式参数的函数
func sayHelloWorld() -> String {
return "hello world"
}
print(sayHelloWorld()) // 多形式参数的函数
func greet(person: String, alreadyGreeted: Bool) -> String {
if alreadyGreeted {
return greetAgain(person: person)
} else {
return greet(person: person)
}
}
greet(person: "tim", alreadyGreeted: true) // 无返回值的函数
func greet(person: String) {
print("hello, \(person)!")
} // 多返回值的函数
func minMax(array: [Int]) -> (min: Int, max: Int) {
var currentMin = array[0]
var currentMax = array[0] for value in array[1..<array.count] {
if value < currentMin {
currentMin = value
} else if value > currentMax {
currentMax = value
}
} return (currentMin, currentMax)
} // 可选元组返回类型
func minMax(array: [Int]) -> (min: Int, max: Int)? { if array.isEmpty {return nil} var currentMin = array[0]
var currentMax = array[0] for value in array[1..<array.count] {
if value < currentMin {
currentMin = value
} else if value > currentMax {
currentMax = value
}
} return (currentMin, currentMax)
} // 隐式返回的函数
// 如果整个函数体是一个单一表达式,那么函数可以隐式返回这个表达式
func greeting(person: String) -> String {
"hello " + person + "!"
}
print(greeting(person: "Tom"))
实参标签、形参名和返回值
/* 每一个函数的形式参数都包含实际参数标签和形式参数名。实际参数标签用在调用函数的时候;在调用函数的时候每一个实际参数前面都要写实际参数标签。形式参数名用在函数的实现当中。默认情况下,形式参数使用它们的形式参数名作为实际参数标签。
所有的形式参数必须有唯一的名字。尽管有可能多个形式参数拥有相同的实际参数标签,唯一的实际参数标签有助于让你的代码更加易读
*/
func someFunction(firstParameterName: Int, secondParameterName: Int) { }
someFunction(firstParameterName: 1, secondParameterName: 3)
上面的中没有定义实际参数标签,所以使用形式参数(firstParameterName、secondParameterName)名作为实参标签。在函数体内部使用形参实现逻辑。 // 指定实际参数标签
/*
在提供形式参数名之前写实际参数标签,用逗号分隔
如果你为一个形式参数提供了实际参数标签,那么这个实际参数就必须在调用函数的时候使用标签
实际参数标签的使用能够让函数的调用更加明确,更像是自然语句,同时还能提供更可读的函数体并更清晰的表达你的意图
*/
func greet(person: String, frome hometown: String) -> String {
return "hello \(person)! Glad you coule visit frome \(hometown)"
}
print(greet(person: "Bill", frome: "Cupertino"))
上面的中第一个参数没有定义实际参数标签,所以使用形式参数(person)名作为实参标签。第二个参数指定了(from)作为实际参数标签,(hometown)作为形式参数名。所以在调用的时候显示了(from),在内部使用(hometown) // 省略实际参数标签 使用_替代
func someFunction(_ firstParameterName: Int, secondParameterName: Int) { }
someFunction(1, secondParameterName: 3)
上面的中第一个使用_来省略实际参数标签 // 默认形式参数值
func someFunction(parameterWithDefault: Int = 12) {
print(parameterWithDefault)
}
someFunction(parameterWithDefault: 44)
someFunction() // 可变形式参数
func arithmeticMean(_ numbers: Double...) -> Double {
var total: Double = 0
for num in numbers {
total += num
}
return total
}
arithmeticMean(1, 2, 3)
arithmeticMean(1) // 输入输出形式参数
/*
可变形式参数只能在函数的内部做改变。如果想函数能够修改一个形式参数的值,而且你想这些改变在函数结束后依然生效,就需要将形式参数定义为输入输出形式参数。
在形式参数定义开始的时候在前面添加一个inout关键字可以定义一个输入输出形式参数。
只能把变量作为输入输出形式参数的实际参数,再将变量作为实际参数传递给输入输出形式参数的时候,直接在它的前面添加一个&来明确可以被函数修改
输入输出形式参数不能有默认值,可变形式参数不能标记为inout
*/
func swapTwoInts(_ a:inout Int, _ b:inout Int) {
let temp = a
a = b
b = temp
} var a = 3
var b = 4;
swapTwoInts(&a, &b)
print(a, b)
函数类型和内嵌函数
// 函数类型由形式参数类型,返回类型组成
func addTwoInts(_ a: Int, _ b: Int) -> Int {
return a + b
}
func muliplyTwoInts(_ a: Int, _ b: Int) -> Int {
return a * b
}
上面两个都是(Int, Int) -> Int 类型 // 使用函数类型
var mathFunction: (Int, Int) -> Int = addTwoInts(_:_:)
print(mathFunction(2, 4))
// 作为参数
func printMathResult(_ mathFunction:(Int, Int) -> Int, _ a: Int, _ b: Int) {
print("result:\(mathFunction(a,b))")
}
printMathResult(addTwoInts(_:_:), 3, 4)
// 作为返回值
func stepForward(_ input: Int) -> Int {
return input + 1
}
func stepBackward(_ input: Int) -> Int {
return input - 1
}
func chooseStepFunction(backwards: Bool) -> (Int) -> Int {
return backwards ? stepBackward(_:) : stepForward(_:)
} // 内嵌函数
func chooseStepFunction(backwards: Bool) -> (Int) -> Int {
func stepForward(_ input: Int) -> Int { return input + 1 }
func stepBackward(_ input: Int) -> Int {
return input - 1
}
return backwards ? stepBackward(_:) : stepForward(_:)
}
闭包
定义
/*
闭包是可以在你的代码中被传递和引用的功能性独立代码块
闭包能够捕获和存储定义在其上下文中的任何常量和变量的引用。
*/ /*
闭包符合如下三种形式中的一种:
1.全局函数是一个有名字但不会捕获任何值的闭包;
2.内嵌函数是一个有名字且能从其上层函数捕获值的闭包;
3.闭包表达式是一个轻量级语法所写的可以捕获其上下文中常量或变量值的没有名字的闭包
*/ // 闭包表达式是一种在简短行内就能写完闭包的语法。
// 闭包表达式语法能够使用常量形式参数、变量形式参数和输入输出形式参数,但不能提供默认值。可变形式参数也能使用,但是需要在形式参数列表的最后使用,元组也可被用来作为形式参数和返回类型
// 结构如下
{ (parameters) -> (return type) in
statements
} // 不使用闭包
let names = ["zhangsan", "lisi", "wangwu", "maliu"]
let fNames = names.sorted() func backward(s1: String, s2: String) -> Bool {
return s1 > s2
}
let sNames = names.sorted(by: backward(s1:s2:)) // 使用闭包
let sNames = names.sorted(by: { (s1: String, s2: String) -> Bool in
return s1 > s2
}) let sName = names.sorted(by:{ s1, s2 in return s1 > s2 } ) // 单表达式闭包能通过从它们的声明中删除return关键字来隐式返回单个表达式的结果
let sName = names.sorted(by:{ s1, s2 in s1 > s2 } ) // swift自动对行内闭包提供间歇实际参数名,可以通过$0,$1,$2等名字来引用闭包的实际参数值
let sName = names.sorted(by:{ $0 > $1 } ) // 运算符函数
/*
swift的String类型定义了关于大于号(>)的特定字符串实现,其类型正好与sorted(by:)所需形参一致,所以可以更简单的书写
*/
let sName = names.sorted(by: > ) // 尾随闭包
/*
尾随闭包是一个被书写在函数形式参数的括号外面(后面)的闭包表达式
条件:只有一个参数,且是一个闭包,可以直接加闭包,并且去掉括号
*/
let sName = names.sorted{$0 > $1 }
闭包捕获值
/*
一个闭包能够从上下文捕获已被定义的常量和变量。即使定义这些常量和变量的原作用域已经不存在,闭包仍能够在其函数体内引用和修改这些值。 在swift中,函数和闭包都是引用类型。 如果你分配了一个闭包给类实例的属性,并且闭包通过引用该实例或者它的成员来捕获实例,你将在闭包和实例间会产生循环引用
*/
逃逸闭包、自动闭包
// 逃逸闭包
// 自动闭包
【学习】重学Swift5-函数和闭包的更多相关文章
- iOS学习笔记42-Swift(二)函数和闭包
上一节我们讲了Swift的基础部分,例如数据类型.运算符和控制流等,现在我们来看下Swift的函数和闭包 一.Swift函数 函数是一个完成独立任务的代码块,Swift中的函数不仅可以像C语言中的函数 ...
- CC2530红外学习球学码函数(P1.2接红外一体接收头,使用定时器tim1的复用功能2)
P1.2GPIO配置: void cap_gpio_init(){ P1SEL |= 0x04; P1DIR &= ~0x04; PERCFG |= 0x40; P2SEL |= 0x20; ...
- scala学习笔记4:函数和闭包
以下主要记录的是看完scala in programming这本书functions and closures(第八章)后的要点总结. 1,函数可以存在的地方:函数方法,嵌套函数. 2,关于funct ...
- javascript进阶课程--第三章--匿名函数和闭包
javascript进阶课程--第三章--匿名函数和闭包 一.总结 二.学习要点 掌握匿名函数和闭包的应用 三.匿名函数和闭包 匿名函数 没有函数名字的函数 单独的匿名函数是无法运行和调用的 可以把匿 ...
- 前端学习 第六弹: javascript中的函数与闭包
前端学习 第六弹: javascript中的函数与闭包 当function里嵌套function时,内部的function可以访问外部function里的变量 function foo(x) { ...
- 记录我的 python 学习历程-Day13 匿名函数、内置函数 II、闭包
一.匿名函数 以后面试或者工作中经常用匿名函数 lambda,也叫一句话函数. 课上练习: # 正常函数: def func(a, b): return a + b print(func(4, 6)) ...
- 【Go语言学习】匿名函数与闭包
前言 入坑 Go 语言已经大半年了,却没有写过一篇像样的技术文章,每次写一半就搁笔,然后就烂尾了. 几经思考,痛定思痛,决定金盆洗手,重新做人,哦不,重新开始写技术博文. 这段时间在研究Go语言闭包的 ...
- JavaScript权威设计--命名空间,函数,闭包(简要学习笔记十二)
1.作为命名空间的函数 有时候我们需要声明很多变量.这样的变量会污染全局变量并且可能与别人声明的变量产生冲突. 这时.解决办法是将代码放入一个函数中,然后调用这个函数.这样全局变量就变成了 局部变量. ...
- 《JS语言精粹》学习笔记 函数部分の闭包
要理解闭包,首先要理解变量作用域,变量的作用域就两种,全局变量和局部变量,函数内部可以直接读取全局变量,函数外部无法读取函数内部的局部变量. 闭包定义:能读取函数内部局部变量的函数就是闭包,而只有函数 ...
- swift 学习(二)基础知识 (函数,闭包,ARC,柯里化,反射)
函数 func x(a:Int, b:Int) {} func x(a:Int, b:Int) -> Void {} func x(a:Int, b:Int) ->(Int,Int ...
随机推荐
- 利用DNSLOG测试XXE漏洞(BWAPP为例)
以BWAPP为例,测试XXE漏洞,用DNSLOG作回显. 一.选择XXE漏洞测试,抓包,点击[anybugs?]. 二.获取域名 三.直接上payload 四.查看DNSLOG回显 如有错误,请及时指 ...
- 使用systemd 监控服务并实现故障自动重启
一.为什么需要自动重启? 在生产环境中,服务可能因内存溢出.资源竞争.外部依赖中断等问题意外崩溃.手动恢复效率低下,而 systemd 的自动重启机制可在秒级内恢复服务,显著提升系统可用性. ⚙️ 二 ...
- PPOCRLabel 无法启动,启动报错排查!!
目前我本地版本为:conda虚拟环境,Python=3.10,Win11系统 1.安装环境必须要有paddlepaddle,安装paddlepaddle. python -m pip install ...
- Luogu P11158 【MX-X6-T4】夢重力 题解
P11158 [MX-X6-T4]夢重力 分类讨论好题. 不难发现交换行等价于交换列,考虑转化贡献体,枚举长度为 \(\frac{n}{2}\) 区间,统计这个区间被多少种交换方式包含. 考虑一个长度 ...
- CF1967B1 Reverse Card (Easy Version) 题解
CF1967B1 Reverse Card (Easy Version) 我们发现 \(b\times\gcd(a,b)\) 必然为 \(b\) 的倍数,那么 \(b\times\gcd(a,b)\) ...
- C语言中如何不用strcat函数来连接2个数组
C语言中如何不用strcat函数来连接2个数组? 今天就遇到这个问题,所以就尝试了一下,虽然这个问题被好多大佬看作就不是问题,但我还是对这方面做个简单的介绍. 下面是我的代码和运行情况. 其实简单的引 ...
- ETL数据集成丨主流ETL工具(ETLCloud、DataX、Kettle)数据传输性能大PK
目前市面上的ETL工具众多,为了方便广大企业用户在选择ETL工具时有一个更直观性能方面的参考值,我们选取了目前市面上最流行的三款ETL工具(ETLCloud.DataX.Kettle)来作为本次性能传 ...
- Linguistics-English-Would, Should, and Could: How to Use Them Correctly
https://7esl.com/would-should-could/ Compare Can, Could and Would Can: capacity Could: possibility W ...
- 主流PLC串口自由协议通信标准化
一.PLC串口自由协议通信概述:串口自由协议通信是一种灵活的串行通信方式.在该模式下,开发者无需遵循特定标准协议,可根据实际需求自由定义数据格式与交互规则.通常需明确数据帧结构,例如设置起始字节.数据 ...
- es6划重点
es6划重点 1.作用域变量 1.1.let和var对比 1.变量不提升 2.不能重复定义 3.暂存死区 4.闭包新写法 2.const(常量) 3.解构 1.数组解构 2.对象解构 3.混合解构 4 ...