上一节咱们讲了Swift的基础部分,例如数据类型、运算符和控制流等,如今咱们来看下Swift的函数和闭包swift
函数是一个完成独立任务的代码块,Swift
中的函数不只能够像C语言中的函数同样做为函数的参数和返回值,并且还支持嵌套,支持函数参数默认值、可变参数等。数组
/* 一、在局部参数名前加上#来简写外部参数名(此时局部参数名和外部参数名相同) 二、若是使用默认参数,那么此参数名将默认做为外部参数名(此时局部参数名和外部参数名相同) 三、可变参数只能在最后一个参数,可变参数的类型是数组 四、返回类型也能够是元组 五、能够在参数前面加 var、let、inout 关键字,var表示该局部变量可变,let表示不可变(默认), inout表示内部修改会改变外部的变量,调用时要加“&”符号 六、Swift中的函数自己也能够看作一种类型,既能够做为参数又能够做为返回值。 例如 var fun:(Int,Int)->(Double,Int) = fun2 */ func 函数名(var #参数1:类型1, inout 参数2:类型2=默认值2, let #可变参数3:类型3...) -> 返回值类型 { 函数体 return 返回值 }
//1. 定义一个函数,注意参数和返回值,若是没有返回值能够不写返回值或者写成Void、空元组() func mySum(num1:Int, num2:Int) -> Int{ return num1 + num2 } //调用函数 mySum(1, 2)
/* 2. 函数参数名分为局部参数名和外部参数名 */ func mySplit(string a:String, seperator b:Character) -> [String]{ //调用系统自带的字符串分割函数 return split(a, maxSplit: Int.max, allowEmptySlices: false, isSeparator: {$0==b}) } /* 因为给mySplit函数设置了外部参数名string和seperator,因此执行的时候必须带上外部参数名, 此处能够看到一个有意义的外部参数名大大节省开发者使用成本 */ mySplit(string: "hello,world,!", seperator: ",") //结果:["hello", "world", "!"]
//3. 下面经过在局部参数名前加上#来简写外部参数名(此时局部参数名和外部参数名相同) func mySplit2(#string:String, #seperator:Character) -> [String]{ //调用系统自带的字符串分割函数 return split(string, maxSplit: Int.max, allowEmptySlices: false, isSeparator: {$0==seperator}) } mySplit2(string: "hello,world,!", seperator: ",") //结果:["hello", "world", "!"]
//4. 设置函数的最后一个参数默认值设置为",",注意若是使用默认参数那么此参数名将默认做为外部参数名 func mySplit3(#string:String, seperator:Character=",")->[String]{ //调用系统自带的字符串分割函数 return split(string, maxSplit: Int.max, allowEmptySlices: false, isSeparator: {$0==seperator}) } mySplit3(string: "hello,world,!") //结果:["hello", "world", "!"] mySplit3(string: "hello world !", seperator: " ") //结果:["hello", "world", "!"]
/* 5. 可变参数,一个函数最多有一个可变参数而且做为最后一个参数 下面strings参数在内部是一个[String],对于外部是不定个数的String参数 */ func myJoinStr(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 } //调用 myJoinStr(seperator:" ", "hello","world","!") //结果:"hello world !"
/* 6. 函数参数默认是常量,不能直接修改,经过声明var能够将其转化为变量(可是注意C语言参数默认是变量) 可是注意这个变量对于外部是无效的,函数执行完就消失了 */ func mySum2(var num1:Int, num2:Int) -> Int{ num1 = num1 + num2 return num1 } mySum2(1, 2) //结果:3
/* 7. 输入输出参数 经过输入输出参数能够在函数内部修改函数外部的变量(注意调用时不能是常量或字面量) 注意:下面的mySwap仅仅为了演示,实际使用时请用Swift的全局函数swap */ func mySwap(inout a:Int ,inout b:Int){ a = a + b b = a - b a = a - b } var a = 1,b = 2 mySwap(&a, &b) //调用时参数加上“&”符号 println("a=\(a),b=\(b)") //结果:"a=2,b=1"
/* * 8. 函数类型 */ var sum3 = mySum //自动推断sum3的类型:(Int,Int)->Int,注意不一样的函数类型之间不能直接赋值 sum3(1,2) //结果:3 //函数做为返回值 func fn() -> (Int,Int)->Int{ //下面的函数是一个嵌套函数,做用因而在fn函数内部 func minus(a:Int, b:Int) -> Int{ return a - b } return minus; } var minus = fn() minus(1, 2) //结果:-1 //函数做为参数 func caculate(num1:Int,num2:Int,fn:(Int,Int)->Int) -> Int{ return fn(num1,num2) } caculate(1, 2, mySum) //结果:3 caculate(1,2, minus) //结果:-1
Swift
中的闭包其实就是一个函数代码块,它和ObjC中的Block
及Java中的lambda
是相似的。
闭包的特色就是能够捕获和存储上下文中的常量或者变量的引用,即便这些常量或者变量在原做用域已经被销毁了在代码块中仍然可使用。闭包
{ ( parameters ) -> returnType in statements; }
func mySum(num1:Int,num2:Int) -> Int{ return num1 + num2 } func myMinus(num1:Int,num2:Int) -> Int{ return num1 - num2 } func myCaculate(num1:Int, num2:Int, fn:(Int,Int)->Int) -> Int{ return fn(num1,num2) } var (a, b) = (1, 2) myCaculate(a, b, mySum) //结果:3 myCaculate(a, b, myMinus) //结果:-1
//利用闭包表达式替代函数mySum myCaculate(a, b, {(num1:Int, num2:Int) -> Int in return num1 + num2 }) //结果:3 //利用闭包表达式替代函数myMinus myCaculate(a, b, {(num1:Int, num2:Int) -> Int in return num1 - num2 }) //结果:-1
//简化形式,根据上下文推断类型而且对于单表达式闭包(只有一个语句)能够隐藏return关键字 myCaculate(a, b, { num1, num2 in num1 + num2 }) //结果:3 myCaculate(a, b, { num1, num2 in num1 - num2 }) //结果:-1
//再次简化,使用参数名缩写,使用$0...$n表明第n个参数,而且此in关键字也省略了 myCaculate(a, b, { $0 + $1 }) //结果:3 myCaculate(a, b, { $0 - $1 }) //结果:-1
考虑到闭包表达式的可读取性,Swift
中若是一个函数的最后一个参数是一个函数类型的参数(或者说是闭包表达式),则能够将此参数写在函数括号以后,这种闭包称之为“尾随闭包”。app
//尾随闭包 myCaculate(a, b) { $0 + $1 } //结果:3 myCaculate(a, b) { $0 - $1 } //结果:-1
前面说过闭包之因此称之为“闭包”,就是由于其能够捕获必定做用域内的常量或者变量进而闭合并包裹着。函数
func myAdd() -> ()->Int { var total = 0 var step = 1 func fn() -> Int{ total += step return total } return fn } /* fn捕获了total和step,尽管下面的myAdd()执行完后total和step被释放, 可是因为fn捕获了两者的副本,因此fn会随着两个变量的副本一块儿被存储 */ var a = myAdd() a() //结果:1 a() //结果:2,说明a中保存了total的副本(不然结果会是1) var b = myAdd() b() //结果:1,说明a和b单独保存了total的副本(不然结果会是3) var c = b c() //结果:2,说明闭包是引用类型,换句话说函数是引用类型(不然结果会是1)
Swift
会自动决定捕获变量或者常量副本的拷贝类型(值拷贝或者引用拷贝)而不须要开发者关心Swift
来管理,咱们不用关心,例如当上面的函数a再也不使用了,那么fn捕获的两个变量也就释放了。