函数
函数是一个完成独立任务的代码块,Swift中的函数不仅可以像C语言中的函数一样有函数的参数和返回值,而且还支持嵌套,并且有函数参数默认值、可变参数等。
1 //定义一个函数,注意参数和返回值,如果没有返回值可以不写返回值或者写成Void、空元组()(注意Void的本质就是空元组) 2 func sum(num1:Int,num2:Int)->Int{ 3 return num1 + num2 4 } 5 6 sum(1, 2)
可以看到Swift中的函数仅仅表示形式有所区别(定义类似于Javascript,但是js不用书写返回值),但是本质区别不大。不过Swift中对函数参数强调两个概念就是局部参数名(又叫“形式参数”)和外部参数名,这增大了开发者的开发体验。在上面的例子中强调了sum函数并没有传递任何参数名,因为num1、num2仅仅作为局部参数名在函数内部使用,但是如果给函数指定一个外部参数名在调用时就必须指定参数名。另外前面也提到关于Swift中的默认参数、可变长度的参数,包括一些高级语言中的输入输出参数,通过下面的例子可以全面的了解。
/** /** * 函数参数名分为局部参数名和外部参数名 */ func split(string a:String,seperator b:Character)->[String]{ return split(a, maxSplit: Int.max, allowEmptySlices: false, isSeparator: {$0==b}) } //由于给split函数设置了外部参数名string和seperator,所以执行的时候必须带上外部参数名,此处可以看到一个有意义的外部参数名大大节省开发者使用成本 split(string: "hello,world,!", seperator: ",") //结果:["hello", "world", "!"] //下面通过在局部参数名前加上#来简写外部参数名(此时局部参数名和外部参数名相同) func split2(#string:String,#seperator:Character)->[String]{ return split(string, maxSplit: Int.max, allowEmptySlices: false, isSeparator: {$0==seperator}) } split2(string: "hello,world,!", seperator: ",") //上面的split函数的最后一个参数默认设置为",",注意如果使用默认参数那么此参数名将默认作为外部参数名(此时局部参数名和外部参数名相同) func split3(#string:String,seperator:Character=",")->[String]{ return split(string, maxSplit: Int.max, allowEmptySlices: false, isSeparator: {$0==seperator}) } split3(string: "hello,world,!", seperator: ",") //结果:["hello", "world", "!"] split3(string: "hello world !", seperator: " ") //结果:["hello", "world", "!"] //但是如果有默认值,又不想指定局部参数名可以使用“_”取消外部参数名 func split4(string:String,_ seperator:Character=",")->[String]{ return split(string, maxSplit: Int.max, allowEmptySlices: false, isSeparator: {$0==seperator}) } split4("hello,world,!", ",") //结果:["hello", "world", "!"] /** * 可变参数,一个函数最多有一个可变参数并且作为最后一个参数 * 下面strings参数在内部是一个[String],对于外部是不定个数的String参数 */ func joinStr(seperator:Character=",",strings:String...)->String{ var result:String="" for var i=0;i<strings.count;++i{ if i != 0{ result.append(seperator) } result+=strings[i] } return result } joinStr(seperator:" ", "hello","world","!") //结果:"hello world !" /** * 函数参数默认是常量,不能直接修改,通过声明var可以将其转化为变量(但是注意C语言参数默认是变量) * 但是注意这个变量对于外部是无效的,函数执行完就消失了 */ func sum2(var num1:Int,num2:Int)->Int{ num1 = num1 + num2 return num1 } sum2(1, 2) //结果:3 /** * 输入输出参数 * 通过输入输出参数可以在函数内部修改函数外部的变量(注意调用时不能是常量或字面量) * 注意:下面的swap仅仅为了演示,实际使用时请用Swift的全局函数swap */ func swap(inout a:Int ,inout b:Int){ a=a+b b=a-b a=a-b } var a=1,b=2 swap(&a, &b) //调用时参数加上“&”符号 println("a=\(a),b=\(b)") //结果:"a=2,b=1"
和很多语言一样,Swift中的函数本身也可以看做一种类型,既可以作为参数又可以作为返回值。
1 /** 2 * 函数类型 3 */ 4 var sum3=sum //自动推断sum3的类型:(Int,Int)->Int,注意不同的函数类型之间不能直接赋值 5 sum3(1,2) //结果:3 6 7 //函数作为返回值 8 func fn()->(Int,Int)->Int{ 9 //下面的函数是一个嵌套函数,作用于是在fn函数内部 10 func minus(a:Int,b:Int)->Int{ 11 return a-b 12 } 13 return minus; 14 } 15 var minus=fn() 16 17 //函数作为参数 18 func caculate(num1:Int,num2:Int,fn:(Int,Int)->Int)->Int{ 19 return fn(num1,num2) 20 } 21 22 caculate(1, 2, sum) //结果:3 23 caculate(1,2, minus) //结果:-1
闭包
Swift中的闭包其实就是一个函数代码块,类似于OC中的block。闭包的特点:可以捕获和储存上下文的常量或者变量的引用,即使这些常量或者变量在原作用域已经被销毁了,但在代码中仍然可以使用。事实上前面的全局函数和嵌套函数也是一种闭包,对于全局函数它不会捕获任何常量或者变量,而对于嵌套函数则可以捕获其所在函数的常量或者变量。通常我们说的闭包更多指的是闭包表达式,也就是没有函数名称的代码块,因此也叫做匿名闭包。
在Swift中闭包表达式的定义形式如下:
{(parameters)->returnType in
statements
}
下面通过一个例子看一下如何通过闭包表达式来简化一个函数类型的参数,在下面的例子中闭包的形式也是一而再再而三的被简化,充分说明了Swift语法的简洁性:
1 func sum(num1:Int,num2:Int)->Int{ 2 return num1 + num2 3 } 4 5 func minus(num1:Int,num2:Int)->Int{ 6 return num1 - num2 7 } 8 9 func caculate(num1:Int,num2:Int,fn:(Int,Int)->Int)->Int{ 10 return fn(num1,num2) 11 } 12 13 var (a,b)=(1,2) 14 15 caculate(a, b, sum) //结果:3 16 caculate(a, b, minus) //结果:-1 17 18 //利用闭包表达式简化闭包函数 19 caculate(a, b, {(num1:Int,num2:Int)->Int in 20 return num1 - num2 21 }) //结果:-1 22 23 //简化形式,根据上下文推断类型并且对于单表达式闭包(只有一个语句)可以隐藏return关键字 24 caculate(a, b, { num1,num2 in 25 num1 - num2 26 }) //结果:-1 27 28 //再次简化,使用参数名缩写,使用$0...$n代表第n个参数,并且此in关键字也省略了 29 caculate(a, b, { 30 $0 - $1 31 }) //结果:-1
考虑到闭包表达式的可读取性,Swift中如果一个函数的最后一个参数是一个闭包表达式,则可以将此参数写在函数括号之后,这种闭包称之为“尾数闭包”。