Swift-25-普通函数、闭包函数与Lamda表达式编程

2024-04-22 06:28

本文主要是介绍Swift-25-普通函数、闭包函数与Lamda表达式编程,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

函数

语法定义

先来看下swift中函数的定义,函数用关键字func来指定,语法相对复杂一点,主要有下列4种基本情况,还有比较复杂的,会在后续详细讲解。

无参函数定义

在这里插入图片描述

有参函数定义

在这里插入图片描述

一个简单的函数和函数调用示例如下:

    func printGreeting1() {print("Hello, playground.")}printGreeting1()func printGreeting2() ->String {return "Hello, playground.";}lef str = printGreeting2()

函数参数

函数有参数(parameter)之后就能做更多的事情了。利用参数可以向函数输入数据。我们之所以把函数的这部分称为“参数”,是因为它们可以根据调用者给函数传递的数据来改变自己的值。函数利用传递给自己的参数来执行任务或产生结果。 创建一个函数,利用参数打印更加个性化的问候信息,代码如下所示:

  //带一个参数func printPersonalGreeting(name: String) {print("Hello \(name), welcome to your playground.")}printPersonalGreeting(name: "Matt")

参数内部名称

语法格式为:paramName:ParamType,前面是参数名称,后面指参数类型。

      //带两个参数func divisionDescriptionFor(numerator: Double, denominator: Double) {print("\(numerator) divided by \(denominator) equals \(numerator / denominator)")}divisionDescriptionFor(numerator: 9.0, denominator: 3.0)

参数外部名称

语法格式为:outParName inParName:ParamType,依次表示外部调用时的参数名称,函数内部使用时的参数名称,参数类型。

这主要是为了代码的可读性更强而设计的,并没其它实际意义,但在调用时名称要匹配,如下例为外部调用重新声了一个名为to的参数名称以专让供外部调用使用。

func printPersonalGreeting(to name: String) { 13 print("Hello \(name), welcome to your playground.")
}
printPersonalGreeting(to: "Matt")

变长参数

语法格式为:paramName:ParamType... 注意最后面的三个点,就是变长参数的特殊关键字。

函数只能有一个变长参数,而且一般应该是函数参数列表中的最后一个。参数值在函数内是以数组的形式使用,比如下例所示:

func printPersonalGreetings(to names: String...) {for name in names {print("Hello \(name), welcome to the playground.")}
}
printPersonalGreetings(to: "Alex","Chris","Drew","Pat")

在这里插入图片描述

参数默认值

语法格式为:paramName:ParamType=value 用=号进行默认值赋值操作。

默认值应该放在函数参数数列表的末尾,如果形参有默认值,那么在调用函数时可以省略实参。

func divisionDescriptionFor(numerator: Double,denominator: Double, withPunctuation punctuation: String = ".") -> String { //默认值设置return "\(numerator) divided by \(denominator) equals \(numerator / denominator)\(punctuation)"
}//9.0 divided by 3.0 equals 3.0.  少传一个参数
print(divisionDescriptionFor(numerator: 9, denominator: 3))
//9.0 divided by 3.0 equals 3.0!  替换默认参数
print(divisionDescriptionFor(numerator: 9, denominator: 3, withPunctuation: "!"))

in-out 参数

语法格式为:paramName:input ParamType ,这里的input是一个关键字。

函数有时候需要修改实参的值。in-out(in-out parameter)能让函数影响函数体以外的变量。有两个注意事项:

  • 首先,in-out不能有默认值;
  • 其次,变长参数不能标记为inout;

in-out的作用其实就是用于实参值的修改,省去return的写法,也可认为是达到多返回的目的。

var error = "The request failed:"
//_是一个外部函数名,它有特殊含义,即如果定义外部参数名为_,则在函数被调用时可以不写参数名称
func appendErrorCode(_ code: Int, toErrorString errorString: inout String) {if code == 400 {errorString += " bad request."}
}//用inout修饰时,调用时需要加上&,表示函数会修改这个变量,此段代码运行最后error的值会被改写成The request failed: bad request. 这有点像return干的事。
appendErrorCode(400, toErrorString: &error)
error

函数返回值

函数结束执行后可以返回一些信息,这些信息称为函数的返回值,用return关键字来标识。

单个返回值

一个简单的例子,如下

func divisionDescriptionFor() -> String {return "numerator"
}var v = divisionDescriptionFor();

多个返回值

语法结构 : ->(name1:[DataType], name2:[DataType]),前面的name1和name2也可以省略,但不建议。

函数可以返回不止一个值。Swift用元组数据类型来做到这一点。

func sortEvenOddNumbers(_ numbers: [Int]) -> (evens: [Int], odds: [Int]) {var evens = [Int]()var odds = [Int]()for number in numbers {if number % 2 == 0 {evens.append(number)} else {odds.append(number)}}return (evens, odds)
}
let aBunchOfNumbers = [10,1,4,3,57,43,84,27,156,111]
let theSortedNumbers = sortEvenOddNumbers(aBunchOfNumbers)//The even numbers are: [10, 4, 84, 156]; the odd numbers are: [1, 3, 57, 43, 27, 111]
print("The even numbers are: \(theSortedNumbers.evens); the odd numbers are: \(theSortedNumbers.odds)")//一个更复杂的例子
func siftBeans(fromGroceryList list: [String]) -> (beanCount: Int, beansBought: [String]) 

多返回值运算

func +(lhs: Point, rhs: Point) -> Point {let newX = (lhs.x + rhs.x)let newY = (lhs.y + rhs.y)return Point(x: newX, y: newY)
}let p1 = Point(x: 1, y: 2)
let p2 = Point(x: 3, y: 5)let p3 = p1 + p2 //(4,7)
p3.x
p3.y

可空类型返回

某些情况下希望函数可返回一个可空实例(用?或!来标识的返回值),主要用于一个函数在某些情况下返回nil,在其它情况下返回一个有意义的实例值的场景

//此函数只有一个参数,参数为元组类型,其中元组的第二个值可有可无的
func grabMiddleName(fromFullName name: (String, String?, String)) -> String? {return name.1 //元组的索引,表示取参数中元组的第二个值,索引从0开始
}//因为函数调用时第二个元组值为nil,所以不会打印任何信息
let middleName = grabMiddleName(fromFullName: ("Matt",nil,"Mathias"))
if let theName = middleName {print(theName)
}

函数返回与中断

主要是用return语句,但这里用了一个特殊的语法guard,熟悉下其用法就可以了。

func greetByMiddleName(name: (first: String, middle: String?, last: String)) {//把middle的值绑定到middleName常量上guard let middleName = name.middle else {print("Hey there!")return}print("Hey \(middleName)!")
}greetByMiddleName(name: ("Matt","Danger","Mathias"))

嵌套函数

Swift的函数定义可以嵌套。嵌套函数在另一个函数定义的内部声明并实现。嵌套函数在包围它的函数以外不可用。当需要一个函数只在另一个函数内部做一些事情时,这个特性很有用。

func areaOfTriangleWith(base: Double, height: Double) -> Double {let numerator = base * height//嵌套函数func divide() -> Double {return numerator / 2}return divide()
}
areaOfTriangleWith(base: 3.0, height: 5.0) //~~ 7.5

声明函数型变量

主要是把函数定义为一个普通变量,这样就可以把函数做为参数传递了,比如下面代码的实现,就是为了把sortEvenOddNumbers做为参数传递。

func sortEvenOddNumbers(_ numbers: [Int]) -> (evens: [Int], odds: [Int]) {return (evens, odds)
}//创建了一个evenOddFunction常量,其值是sortedEvenOddNumbers(_:)函数
let evenOddFunctionType: ([Int]) -> ([Int], [Int]) = sortEvenOddNumbers

闭包

闭包是在应用中完成特定任务的互相分离的功能组,类似于函数但省去了命名和声明,相比函数而言会比较轻量化。先举一个子来一个直观的感受,下面是一个数组排序的例子:

let volunteerCounts = [1,3,40,32,2,53,77,13]func sortAscending(_ i: Int, _ j: Int) -> Bool {return i < j
}
//~~ [1, 2, 3, 13, 32, 40, 53, 77]
let volunteersSorted = volunteerCounts.sorted(by: sortAscending)

如果采用闭包,则代码可以更简单,如下所示:

let volunteerCounts = [1,3,40,32,2,53,77,13]
let volunteersSorted = volunteerCounts.sorted(by: {(i: Int, j: Int) -> Bool inreturn i < j
})

语法结构

基础语法如下例:

{ (parameters) -> return type in // 代码
}
  • 闭包整体代码写在 {} 中;
  • (parameters) 是参数部分;
  • -> return type 表示返回值
  • in 是一个关键字,用来分隔前两部分与代码的实现;

上面的例子还可以再简化:

//简化版本1
let volunteersSorted = volunteerCounts.sorted(by: { i, j in i < j })//简化版本2:$0代表第一个参数,$1代表第二个参数,依此类推,称为快捷语法参数
let volunteersSorted = volunteerCounts.sorted { $0 < $1 }

闭包的写法虽然可以简单再简单,但需要和可读性之间做下权衡,个人还是比较建议用第1种写法,这也是大多数语言的实现方式。

闭包做为函数返回值

一般应用于函数的返回值为另一个函数的场景。下面的makeTownGrand函数返回值为一个函数,注意第一个->后面的(Int, Int) -> Int 其实是一个闭包的写法。

func makeTownGrand() -> (Int, Int) -> Int {func buildRoads(byAddingLights lights: Int, toExistingLights existingLights: Int) -> Int {return lights + existingLights}return buildRoads
}
var stoplights = 4
//此处townPlanByAddingLightsToExistingLights是一个函数变量
let townPlanByAddingLightsToExistingLights = makeTownGrand()
stoplights = townPlanByAddingLightsToExistingLights(4, stoplights)
print("Town has \(stoplights) stop lights.") //Town has 8 stop lights.

闭包做为函数参数

一般应用于函数的参数为另一个函数的场景。下成示例中makeTownGrand函数的第二个参数为一个函数。

func makeTownGrand(withBudget budget: Int, condition: (Int) -> Bool) //第二个参数为一个函数-> ( (Int, Int) -> Int )? { //返回值为函数if condition(budget) {func buildRoads(byAddingLights lights: Int, toExistingLights existingLights: Int) -> Int {return lights + existingLights}return buildRoads} else {return nil}
}//本例子中做为函数参数传统
func evaluate(budget: Int) -> Bool {return budget > 10_000
}var stoplights = 4
//evaluate函数为第二个参数
if let townPlanByAddingLightsToExistingLights = makeTownGrand(withBudget: 1_000, condition: evaluate) {stoplights = townPlanByAddingLightsToExistingLights(4, stoplights)
}if let newTownPlanByAddingLightsToExistingLights = makeTownGrand(withBudget: 10_500, condition: evaluate) {stoplights = newTownPlanByAddingLightsToExistingLights(4, stoplights)
}//~~ Town has 8 stop lights.
print("Town has \(stoplights) stop lights.")

捕获闭包函数内部的变量

闭包和函数能记录在其闭合作用域中定义的变量所封装的内部信息。下面的makePopulationTracker函数的返回值为一函数类型。

func makePopulationTracker(forInitialPopulation population: Int) -> (Int) -> Int {var totalPopulation = populationfunc populationTracker(growth: Int) -> Int {totalPopulation += growthreturn totalPopulation}return populationTracker
}var currentPopulation = 5_422//growBy为一函数
let growBy = makePopulationTracker(forInitialPopulation: currentPopulation) //返回函数(Int) -> Int 
growBy(500) //5922
growBy(500) //6422
growBy(500) //6922
currentPopulation = growBy(500) //7422

再往下写点代码,前两行代码要说明的是闭包是引用类型,当把函数赋给一个常量或变量时,实际上是一个指针引用,并不是副本。但后面两行代码如果通过新的变量指向这个函数,则其作用域变会改变了。

let anotherGrowBy = growBy
anotherGrowBy(500) //7922var bigCityPopulation = 4_061_981
let bigCityGrowBy = makePopulationTracker(forInitialPopulation: bigCityPopulation) //7422bigCityPopulation = bigCityGrowBy(10_000) //4071981

lamda函数式编程

Swift的函数式编程和java差不太多。简单来讲lamda表达式,使代码更简洁,但也更难维护。闭包是实现函数编程的基础,因为函数式编程要求闭包函数可以和其它基本数据类型一样,可作为返回值从别的函数返回,也可以作为参数传递给别的函数,还可以存储在变量中。

map( _: )映射

遍历集合,实现原始数据的变换操作

let precinctPopulations = [1_244, 2_021, 2_157]
let projectedPopulations = precinctPopulations.map {(population: Int) -> Int inreturn population * 2
}
projectedPopulations //[2488, 4042, 4314]

filter( _: )筛选

遍历集合,实现原始数据的筛选

let precinctPopulations = [2488, 4042, 4314]
let bigProjections = projectedPopulations.filter {(projection: Int) -> Bool inreturn projection > 4_000
}
bigProjections //[4042, 4314]

reduce( _ : _ : )统计

遍历集合,实现原始数据的累加统计

let precinctPopulations = [2488, 4042, 4314]
let totalProjection = projectedPopulations.reduce(0) {(accumulatedProjection: Int, precinctProjection: Int) -> Int inreturn accumulatedProjection + precinctProjection
}
totalProjection //10844

这篇关于Swift-25-普通函数、闭包函数与Lamda表达式编程的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/925021

相关文章

Python 异步编程 asyncio简介及基本用法

《Python异步编程asyncio简介及基本用法》asyncio是Python的一个库,用于编写并发代码,使用协程、任务和Futures来处理I/O密集型和高延迟操作,本文给大家介绍Python... 目录1、asyncio是什么IO密集型任务特征2、怎么用1、基本用法2、关键字 async1、async

Kotlin运算符重载函数及作用场景

《Kotlin运算符重载函数及作用场景》在Kotlin里,运算符重载函数允许为自定义类型重新定义现有的运算符(如+-…)行为,从而让自定义类型能像内置类型那样使用运算符,本文给大家介绍Kotlin运算... 目录基本语法作用场景类对象数据类型接口注意事项在 Kotlin 里,运算符重载函数允许为自定义类型重

Pandas中统计汇总可视化函数plot()的使用

《Pandas中统计汇总可视化函数plot()的使用》Pandas提供了许多强大的数据处理和分析功能,其中plot()函数就是其可视化功能的一个重要组成部分,本文主要介绍了Pandas中统计汇总可视化... 目录一、plot()函数简介二、plot()函数的基本用法三、plot()函数的参数详解四、使用pl

Java并发编程之如何优雅关闭钩子Shutdown Hook

《Java并发编程之如何优雅关闭钩子ShutdownHook》这篇文章主要为大家详细介绍了Java如何实现优雅关闭钩子ShutdownHook,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起... 目录关闭钩子简介关闭钩子应用场景数据库连接实战演示使用关闭钩子的注意事项开源框架中的关闭钩子机制1.

Python的time模块一些常用功能(各种与时间相关的函数)

《Python的time模块一些常用功能(各种与时间相关的函数)》Python的time模块提供了各种与时间相关的函数,包括获取当前时间、处理时间间隔、执行时间测量等,:本文主要介绍Python的... 目录1. 获取当前时间2. 时间格式化3. 延时执行4. 时间戳运算5. 计算代码执行时间6. 转换为指

Python正则表达式语法及re模块中的常用函数详解

《Python正则表达式语法及re模块中的常用函数详解》这篇文章主要给大家介绍了关于Python正则表达式语法及re模块中常用函数的相关资料,正则表达式是一种强大的字符串处理工具,可以用于匹配、切分、... 目录概念、作用和步骤语法re模块中的常用函数总结 概念、作用和步骤概念: 本身也是一个字符串,其中

Java中的Lambda表达式及其应用小结

《Java中的Lambda表达式及其应用小结》Java中的Lambda表达式是一项极具创新性的特性,它使得Java代码更加简洁和高效,尤其是在集合操作和并行处理方面,:本文主要介绍Java中的La... 目录前言1. 什么是Lambda表达式?2. Lambda表达式的基本语法例子1:最简单的Lambda表

Spring Boot 集成 Quartz并使用Cron 表达式实现定时任务

《SpringBoot集成Quartz并使用Cron表达式实现定时任务》本篇文章介绍了如何在SpringBoot中集成Quartz进行定时任务调度,并通过Cron表达式控制任务... 目录前言1. 添加 Quartz 依赖2. 创建 Quartz 任务3. 配置 Quartz 任务调度4. 启动 Sprin

shell编程之函数与数组的使用详解

《shell编程之函数与数组的使用详解》:本文主要介绍shell编程之函数与数组的使用,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录shell函数函数的用法俩个数求和系统资源监控并报警函数函数变量的作用范围函数的参数递归函数shell数组获取数组的长度读取某下的

MySQL高级查询之JOIN、子查询、窗口函数实际案例

《MySQL高级查询之JOIN、子查询、窗口函数实际案例》:本文主要介绍MySQL高级查询之JOIN、子查询、窗口函数实际案例的相关资料,JOIN用于多表关联查询,子查询用于数据筛选和过滤,窗口函... 目录前言1. JOIN(连接查询)1.1 内连接(INNER JOIN)1.2 左连接(LEFT JOI