上一節咱們講了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捕獲的兩個變量也就釋放了。