75142913在线留言
【基础篇】3 swift函数与闭包的使用详解_IOS开发_网络人

【基础篇】3 swift函数与闭包的使用详解

Kwok 发表于:2021-01-31 15:31:32 点击:5 评论: 0

swift的函数与其它编程语言在使用上差不多,但是个性化的苹果公司也做了那么一点点的修改让它变得另类。在实际开发使用中我们需要熟记函数的特点即可。swift的函数可以不返回值、返回单个值、返回多个值、返回一个函数,还可以闭包。

一、函数的标准定义:

1、标准的函数定义与调用:

通常情况下我们定义的函数在下面的演示代码:

func myFunc(name:String,sex s:Bool)-> String{
    return name + "是一个" + (s ? "男" : "女") + "人"
}
print(myFunc(name: "张三", sex: true)) //张三是一个男人

和go语言一样使用func修饰一个myFunc的自定义函数,括号是传入函数里参数1:name:String类型,参数2的sex是变量的tag标签,提升函数的可读性,当然可以不使用。-> 后面就是函数的返回值类型,没有返回值可以不写或者写为->void。

调用函数的时候swift强制要求写上变量参数的名字,如果指定了tag就必须写tag名。

2、无参数与返回值的函数:

func welcome(){
    print("欢迎访问neter8.com")
}

3、可变参数(多个不确定参数)

变长参数接受0个或者多个输入值作为参数,一个函数只能有一个可变参数且必须是参数的最后一个,参数在内部以数组的形式存在。

func welcome(names:String...){
    for name in names{
        print("欢迎" + name + "访问neter8.com")
    }
}
welcome(names: "张三","李四","王五")
/*
 欢迎张三访问neter8.com
 欢迎李四访问neter8.com
 欢迎王五访问neter8.com
*/

4、参数默认值

swift的参数可以接受默认值,默认值应该放到参数的后面,如果形参有默认值,那么调用的时候可以省略实参。

func welcome(name:String = "美食圈",url:String = "meishiq.com"){
        print("欢迎访问:" + name + url)
}
welcome(name: "网络人", url: "neter8.com") //欢迎访问:网络人neter8.com
welcome() //欢迎访问:美食圈meishiq.com

二、函数的一些高级用法

swift里有一些与其它语言不相同的用法,在实际开发过程中是非常有用的。

1、inout修饰参数:

加上这个参数可以修改函数传入的外部变量值,类似于GO和PHP里的传内存指针。可以通过下面的代码了解使用方法:

var say = "我是:"
func sayScore(_ score: Int , name: inout String){
    name += "张三,成绩为:" + String(score)
}
sayScore(99,name:&say)//调用函数和GO一样传say变量的内存地址&say
print(say) //say外部变量的值被函数在内部修改为了:我是:张三,成绩为:99

 上面我们说到了函数调用的时候需要写上参数的名字,但这个函数调用的时候直接写了99没有写score参数,是因为我们使用了(_)来忽略参数名,这们可以让我们更灵活的使用函数(自以为是的牵强解释)。

2、函数的嵌套和作用域

嵌套函数是在另一个函数里声明并实现,这个在函数里声明的函数可以访问当前函数的值。

func sum(_ a:Int,_ b:Int) -> Int{
    var c = 5
    func addAll() -> Int{
        return a + b + c
    }
    return addAll()
}
print(sum(1, 2))//1+2+5=8,所以结果为8

声明在函数内容的addAll是没有参数的,但是可以访问到sum函数里传入的参数与内容定义的变量。函数变量的作用域只会在函数内部,我们在外部去访问函数内部定义的c就会报错。这和大部分语言的特性差不多的。

3、函数多个返回值

swift和GO语言一样支持多个返回值,而swift使用元组的方式来实现的。 

func muFunc(_ x: Int) -> (Int,Int) {
    return (x+1,x-1)
}
var a:Int,b:Int//定义2个变量来接收返回值
(a,b) = muFunc(8)
print(a,b)//9 7
var ab = muFunc(6)//返回给元组
print(ab)//(7, 5)

 4、深入学习Void

在最上面的示例写入了一个无参数无返回值的函数:welcome(),实际上没有显式返回式的函数其实还是有返回值的,也就是Void。按住键盘上的command点击Viod跳转到定义可以看到:public typealias Void = (),()是类别名,也就是说Void是一个空元组。通过对Viod的理解我们可以把下面的函数理解是同一个函数

func welcome(){}//程序员常的
func welcome() -> Void{}//编辑器自己加的
func welcome() -> (){}//底程实现的

5、将变量声明为函数类型

swift也可以将变量声明为函数函数类型。规则及代码演示如下:

func sum(_ i: Int, _ j: Int) -> Int {
    return i + j
}
var sumVar: (Int, Int) -> Int = sum
print("输出结果: " + String(sumVar(5, 6)))//11

6、函数类型作为参数类型、函数类型作为返回类型

同时函数也可以做为参数带入到其它函数里使用,也可以做为其它函数的返回值:

func sum(_ i: Int, _ j: Int) -> Int {
    return i + j
}
var sumVar: (Int, Int) -> Int = sum

func printSum(sumVar: (Int, Int) -> Int,i : Int , j : Int){
    print("输出结果: " + String(sumVar(i, j)))
}

printSum(sumVar:sum,i:5,j:6)//11

三、函数闭包closures

每个语言的函数闭包理解起来都会有一点伤脑子,所以单独罗列出来解释。因为很多时候我都需要闭包帮我们处理逻辑事务。

swfift的闭包是为了完成特定任务分享出来的功能组,上面学习的函数嵌套是可理解为有名字的闭包,是闭包的特殊情况,下面我们要学习的是使用匿名函数访问父函数里的值,闭包与函数不同的地方在于其语法更加紧凑、轻量。

 1、逐步理解闭包

在swift里闭包的经典实现就是对数组的排序,首面我们使用函数实现排序转为闭包方式。

let numbers = [11,22,99,44,55,88,77,66,33]//准备一个待排列的数组
//定义一个从大到小排序规则的函数
func orderBydDesc(_ i:Int,_ j:Int) -> Bool{
    return i > j
}
let num = numbers.sorted(by:orderBydDesc)//使用orderBydDescc规则对数组排序
print(num)//[99, 88, 77, 66, 55, 44, 33, 22, 11]

下面我们可以闭包实现从小到大的排序:

let numbers = [11,22,99,44,55,88,77,66,33]//准备一个待排列的数组
let num = numbers.sorted(by:{(i:Int,j:Int) -> Bool in
        return i < j
})//使用闭包实现从小到大的排序
print(num)//[11, 22, 33, 44, 55, 66, 77, 88, 99]

2、闭包的语法

从上面的代码里我们就可以看到闭包的语法只多了一个in。语法结构如下:

//中文解释
{(参数) -> 返回类型 in
        //逻辑代码
}


//英文解释
{(parameters) -> return type in
        //code
}


//上面例子代码剥离
{(i:Int,j:Int) -> Bool in
        return i < j
}

闭包表达式是写在({})花括号里的紧跟左花括号的圆括号里是闭包的参数,闭包的返回值是在参数后面和函数一样的格式,和常规的语法一样,关键字in用于分隔闭包的参数。

3、简化闭包

闭包可以利用swift的类型推导来进一步的简化闭包。上面的代码改进如下:

let num = numbers.sorted(by:{i , j in i < j})//闭包简化写法

上面代码共改了3处,首先移除了返回值和类型信息,因为编译器知道检查i < j是否成立会返回布尔值。

其次,把整个闭包表达式改为了1行。

最后,移除了关键字return,不是所有闭包都可以省略return,这里可以是因为只有一个表达式( i < j ),如果存在更多表达式,那么显式的return就是必须的。

上面的代码够简洁了吧,但还是有进一步的优化空间,这也得力于swift的个性吧,它提供了快捷参数名,可以在内联包表达式中引用,第一个参数以$0表示,第2个参数以$1以此类推,第3个就是$2..........

所以这意味着不需要给参数命名就能直接访问。

let num = numbers.sorted(by:{$0 < $1})//快捷参数

果然每一种编辑语言都会给新学编程的人一顿毒打,swift也不例外。。。。看了上面的代码是不是觉得越来越晕了。。。。

下面开始抽筋拨骨,因为这并不是最简化的写法。。。。。

如果闭包是一个函数的最后一个参数传递的,那么它就可以在函数的圆括号以外内联,因为sorted(by:)只接受一个参数,所以根本不需要圆括号,代码如下:

let num = numbers.sorted{$0 < $1}//省略圆括号的快捷参数

这种尾部闭包的语法对于包体很长的情况特别有用,在这里,尾部闭包只让我们少输入2个圆括号,从上面的语法精简就可以知道苹果把手机的拨号健取消、耳机口取消、HOME键取消,现在充电器和耳机也取消了。我都怀疑后面会不会取消手机。。。。也许这就是“简洁是智慧的灵魂”最好的诠释吧!

到这里也话你认为代码应该减少到极致了吧,但并不是。因为还有更精简的方式。。。

let num = numbers.sorted(by: <)//呵呵括号又回来了,但代码却少了

为了更好的理解swift的闭包,下面更写一些关于闭包的用法,以供理解。今后在看人家代码的时候才不会觉得原来还可以这样用。。。。

let siteName = { print("neter8.com 网络人。") }
siteName()//利用闭包打印:neter8.com 网络人。

4、高阶函数

上面代码里的sorted就是高阶函数之一,高阶函数至少接受一个函数作为参数输入,下面再来看看经常会使用到的其它3个高阶函数:

a.map(_:) 用来改变数组的值内容。

let numbers = [11,22,99,44,55,88,77,66,33]//准备一个待排列的数组
let num = numbers.map{
    (s:Int) -> Int in
    return s + 1 //让数组里的每个值都+1
}
print(num)//[12, 23, 100, 45, 56, 89, 78, 67, 34]

b.fillter(_:) 按条件过滤数组里的值

let numbers = [11,22,99,44,55,88,77,66,33]//准备一个待排列的数组
let num = numbers.filter{
    (s:Int) -> Bool in
    return s > 30 //过滤掉小于30的值
}
print(num)//[99, 44, 55, 88, 77, 66, 33]

c.reduce(_:_:) 将数组里的值按条件组合成1个值

let zhi = ["我","是","张","三"]//准备一个单个字的数组
let ju = zhi.reduce("前缀:"){
    (i:String,j:String) -> String in
    return i + j //将数组组合成一句话
}
print(ju)//前缀:我是张三

reduce除了拼接字符,也可以做运算,比如计算数组里所有值的和,前缀做为一个附加值0即可。

reduce(_:_:) 第一个参数是开始累加的初始值(上面为“前缀”),第二个参数是一个闭包,定义了合并数组值的规则。上面语句使用了闭包尾部语法,也可以使用闭包标准语法去写。

四、断言与拦截

有时候代码运行不符合预期的时候(特别是DeBUG)我们需要对代码进行断言与拦截。

1、断言(assert)的用法

assert可以帮助开发者比较容易的发现和定位错误,一个断言断定条件是true.通过声明一个断言来确保某个必要的条件是满足的,以便继续执行接下来的代码。如果条件满足了,那么代码像往常一样执行,如果不满足了,代码就停止执行了,应用也随之停下来了。

assert(true, "条件成立程序终止!")//强制结束程序,并打印相关信息:assertion failed: 条件成立程序终止!: file /...

let a = 3
for i in 0...a{
   assert(i > a, "程序运行异常!")
}

2、拦截(guard)的用法

guard用于函数里的判断拦截作用,如果条件值为false执行guard代码块内的语句。如果条件值为true不执行guard代码块内的语句。

guard 条件(bool) else { 
    //必须包含一个控制语句:return,break,continue或throw。
}

guard大部分时候用于减少if...else语句,guard条件可以有多个使用英文逗号隔开即可

//传统处理方式
func login(login:login){
    if let userName = login.userNameOK {
        if let password = login.passwordOK {
            // 登录处理
        } else {
            fatalError("login wrong")
        }
    } else {
        fatalError("login wrong")
    }
}

//使用guard处理方式
func login(login:login){
    guard let userName = login.userNameOK,let password = login.passwordOK,else {
        fatalError("login wrong")
    }
    // 登录处理
}
除非注明,网络人的文章均为原创,转载请以链接形式标明本文地址:http://www.neter8.com/ios/101.html
标签:函数funcKwok最后编辑于:2021-03-12 10:12:36
0
感谢打赏!

《【基础篇】3 swift函数与闭包的使用详解》的网友评论(0)

本站推荐阅读

热门点击文章