上一節(jié)我們講了Swift的基礎部分号涯,例如數(shù)據(jù)類型、運算符和控制流等孝偎,現(xiàn)在我們來看下Swift的函數(shù)和閉包
一映皆、Swift函數(shù)
函數(shù)是一個完成獨立任務的代碼塊挤聘,Swift
中的函數(shù)不僅可以像C語言中的函數(shù)一樣作為函數(shù)的參數(shù)和返回值,而且還支持嵌套捅彻,支持函數(shù)參數(shù)默認值组去、可變參數(shù)等。
/**
* 1步淹、函數(shù)第一個參數(shù)默認沒有外部參數(shù)名从隆,其他參數(shù)默認有
* 2、可變參數(shù)只能在最后一個參數(shù)缭裆,可變參數(shù)的類型是數(shù)組
* 3键闺、返回類型也可以是元組
* 4、可以在參數(shù)前面加inout關鍵字幼驶,表示內部修改會改變外部的變量,調用時要加“&”符號
* 5韧衣、Swift中的函數(shù)本身也可以看做一種類型盅藻,既可以作為參數(shù)又可以作為返回值。
例如 var fun:(Int,Int)->(Double,Int) = fun2
*/
func 函數(shù)名(參數(shù)1:類型1, inout 參數(shù)2:類型2=默認值2, 可變參數(shù)3:類型3...) -> 返回值類型 {
函數(shù)體
return 返回值
}
函數(shù)實例:
1. 普通函數(shù)
//1. 定義一個函數(shù)畅铭,注意參數(shù)和返回值氏淑,如果沒有返回值可以不寫返回值或者寫成Void、空元組()
func mySum(num1:Int, num2:Int) -> Int{
return num1 + num2
}
//調用函數(shù)硕噩,num2是外部參數(shù)名假残,函數(shù)第一個參數(shù)默認沒有外部參數(shù)名,其他參數(shù)默認有
mySum(1, num2: 2)
2. 設置外部參數(shù)名
/**
* 2. 函數(shù)參數(shù)名分為局部參數(shù)名和外部參數(shù)名
*/
func mySplit(string a:String, seperator b:Character) -> [String]{
return ["hello", "world", "!"]
}
/*
由于給mySplit函數(shù)設置了外部參數(shù)名string和seperator,所以執(zhí)行的時候必須帶上外部參數(shù)名辉懒,
此處可以看到一個有意義的外部參數(shù)名大大節(jié)省開發(fā)者使用成本
*/
mySplit(string: "hello,world,!", seperator: ",") //結果:["hello", "world", "!"]
3. 設置默認參數(shù)值
//3. 設置函數(shù)的最后一個參數(shù)默認值設置為",",注意如果使用默認參數(shù)那么此參數(shù)名將默認作為外部參數(shù)名
func mySplit3(string:String, seperator:Character=",")->[String]{
return ["hello", "world", "!"]
}
mySplit3("hello,world,!") //結果:["hello", "world", "!"]
mySplit3("hello world !", seperator: " ") //結果:["hello", "world", "!"]
4. 設置可變參數(shù)
/**
* 4. 可變參數(shù),一個函數(shù)最多有一個可變參數(shù)并且作為最后一個參數(shù)
* 下面strings參數(shù)在內部是一個[String]阳惹,對于外部是不定個數(shù)的String參數(shù)
*/
func myJoinStr(seperator 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:" ", strings: "hello","world","!") //結果:"hello world !"
5. 設置輸入輸出參數(shù)
/**
* 5. 輸入輸出參數(shù)
* 通過輸入輸出參數(shù)可以在函數(shù)內部修改函數(shù)外部的變量(注意調用時不能是常量或字面量)
* 注意:下面的mySwap僅僅為了演示,實際使用時請用Swift的全局函數(shù)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: &b) //調用時參數(shù)加上“&”符號
print("a=\(a),b=\(b)") //結果:"a=2,b=1"
6. 函數(shù)類型使用
/**
* 6. 函數(shù)類型
*/
var sum3 = mySum //自動推斷sum3的類型:(Int,Int)->Int,注意不同的函數(shù)類型之間不能直接賦值
sum3(1,num2: 2) //結果:3
//函數(shù)作為返回值
func fn() -> (Int,Int)->Int{
//下面的函數(shù)是一個嵌套函數(shù)眶俩,作用于是在fn函數(shù)內部
func minus(a:Int, b:Int) -> Int{
return a - b
}
return minus;
}
var minus = fn()
minus(1,2) //結果:-1
//函數(shù)作為參數(shù)
func caculate(num1:Int,num2:Int,fn:(Int,Int)->Int) -> Int{
return fn(num1,num2)
}
caculate(1,num2: 2,fn: mySum) //結果:3
caculate(1,num2: 2,fn: minus) //結果:-1
二莹汤、閉包
Swift
中的閉包其實就是一個函數(shù)代碼塊,它和ObjC中的Block
及Java中的lambda
是類似的颠印。
閉包的特點就是可以捕獲和存儲上下文中的常量或者變量的引用纲岭,即使這些常量或者變量在原作用域已經(jīng)被銷毀了在代碼塊中仍然可以使用。
在Swift中閉包表達式的定義形式如下:
{ ( parameters ) -> returnType in
statements;
}
閉包使用:
1. 不使用閉包线罕,使用函數(shù)
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, num2: b, fn: mySum) //結果:3
myCaculate(a, num2: b, fn: myMinus) //結果:-1
2. 使用閉包
//利用閉包表達式替代函數(shù)mySum
myCaculate(a, num2: b, fn: {(num1:Int, num2:Int) -> Int in
return num1 + num2
}) //結果:3
//利用閉包表達式替代函數(shù)myMinus
myCaculate(a, num2: b, fn: {(num1:Int, num2:Int) -> Int in
return num1 - num2
}) //結果:-1
3. 閉包的簡化形式
//簡化形式,根據(jù)上下文推斷類型并且對于單表達式閉包(只有一個語句)可以隱藏return關鍵字
myCaculate(a, num2: b, fn: { num1, num2 in
num1 + num2
}) //結果:3
myCaculate(a, num2: b, fn: { num1, num2 in
num1 - num2
}) //結果:-1
4. 閉包繼續(xù)簡化止潮,使用參數(shù)縮寫
//再次簡化,使用參數(shù)名縮寫,使用$0...$n代表第n個參數(shù)钞楼,并且此in關鍵字也省略了
myCaculate(a, num2: b, fn: { $0 + $1 }) //結果:3
myCaculate(a, num2: b, fn: { $0 - $1 }) //結果:-1
考慮到閉包表達式的可讀取性喇闸,Swift
中如果一個函數(shù)的最后一個參數(shù)是一個函數(shù)類型的參數(shù)(或者說是閉包表達式),則可以將此參數(shù)寫在函數(shù)括號之后窿凤,這種閉包稱之為“尾隨閉包”仅偎。
5. 尾隨閉包
//尾隨閉包
myCaculate(a,num2: b) {
$0 + $1
} //結果:3
myCaculate(a,num2: b) {
$0 - $1
} //結果:-1
6. 捕獲變量
前面說過閉包之所以稱之為“閉包”,就是因為其可以捕獲一定作用域內的常量或者變量進而閉合并包裹著雳殊。
func myAdd() -> ()->Int {
var total = 0
var step = 1
func fn() -> Int{
total += step
return total
}
return fn
}
/*
fn捕獲了total和step橘沥,盡管下面的myAdd()執(zhí)行完后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仓洼,說明閉包是引用類型介陶,換句話說函數(shù)是引用類型(否則結果會是1)
Swift
會自動決定捕獲變量或者常量副本的拷貝類型(值拷貝或者引用拷貝)而不需要開發(fā)者關心
- 被捕獲的變量或者常量的內存管理同樣是由
Swift
來管理,我們不用關心色建,例如當上面的函數(shù)a不再使用了哺呜,那么fn捕獲的兩個變量也就釋放了。