04-Swift函數(Functions)

函數是用來完成特定任務的獨立的代碼塊酒甸。可以給函數起一個名字赋铝,用于標識一個函數插勤,當函數需要執(zhí)行的時候,這個名字就會用于"調用"函數革骨。
?在swift中农尖,每個函數都有一種類型,包括函數的參數值類型和返回值類型良哲。你可以把函數類型當做和其他普通變量類型一樣處理盛卡,這就可以更簡單的把函數當做其他的函數的參數,也可以從其他函數中返回函數筑凫。


一滑沧、函數定義與調用


  • 函數的定義與調用喇颁。func是函數的關鍵字,參數是在函數名后的括號中嚎货,指定函數返回值類型時橘霎,用返回箭頭->后面跟著返回類型的方法是來表示。
/** 
func前綴即表示為函數
函數名: sayHello
參數名: persionName殖属,類型是String 
返回值: 返回值是String類型的
*/
func sayHello(personName:String) -> String {
    let getString = "hello," + personName;
    return getString;
}
// 函數的調用
let str = sayHello("EndEvent");
print(str);
輸出結果: hello,EndEvent


二姐叁、函數參數與返回值


  • 無參函數,即函數可以是沒有參數的:
func speak() -> String{
    // 返回字符串
    return "hello Swift!";   
}
// 函數調用
print(speak());
輸出結果: hello Swift!
  • 多參函數洗显,多個參數以,逗號分隔:
// 參數1: name;   參數2: age;
func sayHi(name:String, age:Int) -> String {
    return "hi外潜,我叫\(zhòng)(name),今年\(age)歲.";
}
print(sayHi("EndEvent", age: 20));
輸出結果: hi挠唆,我叫EndEvent处窥,今年20歲.
  • 無返回值函數,即沒有返回值:
func sayBye(name:String) {
    print("Bye \(name)!");
}
sayBye("EndEvent");
// 輸出結果: Bye EndEvent!
(備注: 雖然沒有返回值定義玄组,但實際`sayBye(_:)`函數依然是返回了值滔驾。這是一個特殊的返回值,叫`void`俄讹。其實返回是一個空的元組`tuple`哆致,沒有任何元素可以寫成`()`)
  • 多重返回值函數,可以用元組(tuple)類型讓多個值作為一個復合值返回:
// 該函數中帶3個參數患膛,返回值是一個元組
func getMaxAndMinValue(a:Int, b:Int, c:Int) -> (max:Int, min:Int){
    // 計算最大值的方法(系統(tǒng)自帶)
    let maxValue = max(a, b, c);
    // 計算最小值的方法(系統(tǒng)自帶)
    let minValue = min(a, b, c);
    
    return (maxValue,minValue);
}
let temp = getMaxAndMinValue(10, b: 3, c: 11);
// 因為元組成員值已命名摊阀,即可用點語法
print("maxValue:\(temp.max)");
print("minValue:\(temp.min)");
輸出結果: 
maxValue:11
minValue:3
  • 可選元組返回類型。如果函數返回的元組類型踪蹬,可能整個元組都是"空的",那么久可以使用* 可選的(Optional) *元組進行返回胞此,這就表示整個元組是nil。例如(Int, Int)?跃捣、(String, String)?漱牵。
func getMaxAndMinValue(array: [Int]) -> (max: Int, min: Int)? {
    if array.isEmpty {  // 表示數組為空
        return nil     
    }
    
    var currentMin = array[0]
    var currentMax = array[0]
    // 遍歷數組
    for value in array[1..<array.count] {
        if value < currentMin {
            currentMin = value
        } else if value > currentMax {
            currentMax = value
        }
    }
    return (currentMax, currentMin)
}
// 函數調用,不為空才打印輸出
if let temp = getMaxAndMinValue([10,3,13,100,-50]) {
    print("maxValue:\(temp.max)");
    print("minValue:\(temp.min)");
}
輸出結果:
maxValue:100
minValue:-50

注意: 可選元組類型如(Int, Int)?和 元組中包含可選類型如(Int?, Int?)是不一樣的枝缔〔几恚可選的元組類型蚊惯,整個元組是可選的愿卸,而不是元組中的每個元組值。


三截型、函數參數名稱


函數參數都有一個* 外部參數名 和 一個 局部參數名 *趴荸。外部參數名用于在函數調用時標注傳遞給函數的參數,內部參數名在函數的內部使用宦焦。
?一般情況下发钝,第一個參數省略其外部參數名顿涣,第二個以及隨后的參數使用其局部參數名作為外部參數名。所有局部參數名必須是獨一無二的酝豪。盡管多個參數可以有相同的外部參數名涛碑,但不同的外部參數名可以提高代碼的可讀性。

  • 指定外部參數名
// firstName: 第一個參數的外部參數名
// name: 第一個參數的內部參數
func sayHello (firstName name:String) {
    print("hello \(name)");
    // 錯誤的孵淘,因為外部參數只用于標注傳遞
    // print("hello \(firstName)"); 
}
// 有提供外部參數名蒲障,在調用時,必須使用外部參數名!!!
sayHello(firstName: "EndEvent");
輸出結果: hello EndEvent
// 外部參數名和內部參數名可以是一樣的
func sayHello (name name:String) {
    print("hello \(name)");
}
sayHello(name: "EndEvent");
輸出結果: hello EndEvent
// 所有外部參數名都可以是一樣的瘫证,即都為name
// 內部參數名是要在函數內使用揉阎,所以必須是不同
func sayHello (name name1:String, name name2:String) {
    print("hello \(name1)");
    print("hello \(name2)");
}
sayHello(name: "EndEvent", name: "Swift");
輸出結果:
hello EndEvent
hello Swift
  • 忽略外部參數,如果不想為第二個以及后續(xù)的參數設置外部參數名背捌,可以用_來代替一個明確的參數名:
// 第一個參數默認忽略其外部參數名稱毙籽,顯式寫下劃線是多余的
func sayHello (name1:String, _ name2:String) {
    print("hello \(name1)");
    print("hello \(name2)");
}
sayHello("EndEvent", "Swift");
輸出結果: 
hello EndEvent
hello Swift
  • 默認參數值,即可以給函數體中每個參數定義默認值毡庆。如果有默認值坑赡,在調用的時候可以忽略此參數:
// 參數style是有默認值的
func goHome (name: String, style: String = "走路") {
    print("\(name)是\(style)回家的");
}
goHome("EndEvent");  // 可以忽略style參數
goHome("Swift",style: "飛");
goHome("liming", style: "開車");
輸出結果:
EndEvent是走路回家的
Swift是飛回家的
liming是開車回家的

注意: 將帶有默認值的參數放在函數參數列表的最后,這可以保證在函數調用時么抗,非默認參數的順序的一致性垮衷,同時在相同函數在不同情況下調用時顯得更為清晰。

  • 可變參數乖坠,可變參數表示可以不接收或接收多個值搀突。通過在變量類型們后加入...的方法來定義可變參數:
// 計算平均值方式,參數是可變的
func arithmeticMean(numbers:Int...) -> Float {
    var total:Float = 0;
    var sum = 0;
    for number in numbers {
        sum += number;
    }
    total = Float(sum) / Float(numbers.count);
    
    return total;
}
let total = arithmeticMean(1,2,3,4,5,6,7,8,9);
print(total);
輸出結果: 5.0

注意: 一個函數中最多只能有一個可變參數熊泵。

  • 常量參數和變量參數仰迁。函數參數默認是常量,試圖在函數體重修改參數值這會導致編譯出錯顽分。但有時候如果想修改參數值徐许,那么久可以將參數定義為變量參數:
func myAppend(var str:String) -> String {
    str.appendContentsOf(" --- haha");
    return str;
}
print(myAppend("EndEvent"));
輸出結果: EndEvent --- haha

注意: 對于變量參數,在函數調用結束后便會消失卒蘸,即是變量參數僅僅存在于函數調用的生命周期中雌隅。

  • 輸入輸出參數。如果想要在一個函數可以修改參數的值缸沃,并且在函數調用結束后仍然存在恰起,即可以把這個參數定義為* 輸入輸出參數(In-Out Parameters) *
// 值的交換
func swapTwoInts(inout a:Int, inout b: Int) {
    let tempValue = a;
    a = b;
    b = tempValue;
}
// 定義兩個變量,并初始化
var a = 10;
var b = 30;
// 調用函數交換兩個變量的值
swapTwoInts(&a, b: &b);
print("a = \(a)");
print("b = \(b)");
輸出結果: a = 30    b = 10

注意:輸入輸出參數和返回值不一樣趾牧,其實這就是將變量的地址傳過去检盼,在函數體中通過變量的地址進行修改值。


四翘单、函數類型


每個函數都有特定的函數類型吨枉,由函數的參數類型和返回值類型組成蹦渣。

  • 使用函數類型。在swift中貌亭,使用函數類型就像使用其他類型一樣:
// 相加函數
func sumFunc(a:Int, b:Int) -> Int {
    return a + b;
}
// 相乘函數
func mathFunc(a:Int, b:Int) -> Int {
    return a * b;
}
// 定義變量str柬唯,類型為(Int,Int) -> Int
var str:(Int,Int) -> Int = sumFunc;      
// 調用相加函數
print("10 + 20 = \(str(10, 20))");
// 給str這個變量賦值一個函數
str = mathFunc;
// 調用相乘函數
print("10 * 20 = \(str(10, 20))");
輸出結果: 10 + 20 = 30    10 * 20 = 200
  • 函數類型作為參數類型。即你可以將(Int, Int) -> Int這樣的函數類型作為另外一個函數的參數類型:
// 相乘函數
func mathFunc(a:Int, b:Int) -> Int {
    return a * b;
}
// 輸出函數
func printMathFuncResult(mathFunc:(Int, Int) -> Int, a:Int, b:Int){
    print("\(a) * \(b) = \(mathFunc(a,b))");
}
// 調用輸出函數
printMathFuncResult(mathFunc, a: 10, b: 10);
輸出結果: 10 * 10 = 100

注意: 可能認為這和函數調用效果是一樣圃庭,現在這是否多此一舉权逗?其實不是,printMathFuncResult (_:_:_:)函數作用是輸出另外一個適當類型的數學函數的調用結果冤议。即在這里只關心傳入的函數類型是否正確斟薇,而不在意函數如何實現。printMathFuncResult (_:_:_:)就是以一種安全類型(type-safe)的方式恕酸,將部分功能轉給調用者實現堪滨,也即是方便代碼的封裝。

  • 函數類型作為返回類型蕊温「は洌可以將函數類型作為另外一個函數的返回類型:
// 實現功能: 將currentInput值變?yōu)?的過程
var currentInput = -5;
// 加操作
func stepForward(input:Int) -> Int {
    return input + 1;
}
// 減操作
func stepBackward(input:Int) -> Int {
    return input - 1;
}
// 函數選擇,參數為input义矛,返回值為'(Int) -> Int'類型
func chooseStepFunction(isBackward:Bool) -> (Int) -> Int {
    // YES:即表示currentInput值是大于0的发笔,選擇stepBackward減操作
    // NO: 即表示currentInput值是小于0的,即選擇stepForward加操作
    return isBackward ? stepBackward : stepForward;
}
// 循環(huán)操作凉翻,直到currentInput為0
while currentInput != 0 {
    print("currentInput: \(currentInput)");
    // 根據currentInput值了讨,選擇對應操作的函數
    var moveNearerToZero = chooseStepFunction(currentInput > 0);
    // 調用操作
    currentInput = moveNearerToZero(currentInput);
}
print("結束操作:\(currentInput)");
輸出結果:
currentInput: -5
currentInput: -4
currentInput: -3
currentInput: -2
currentInput: -1
結束操作:0


五、嵌套函數


在本節(jié)文章中你說見到函數都是* 全局函數(global functions) 制轰,它們都是屬于全局域的前计。但你也可以將函數定義在函數體中,而這種稱之為 嵌套函數(nested functions) 垃杖。
?
嵌套函數 ,在默認情況下對外界是不可見的男杈,但卻可以被它們的 外圍函數(enclosing function) *調用。并且外圍函數也可以返回其所嵌套的函數调俘,使得這個函數也可以在其他域中被調用伶棒。

// 實現功能: 輸入一個值,將值變?yōu)?的過程
var currentInput = -5;
// 函數選擇 - 全局函數
func chooseStepFunction(isBackwark:Bool) -> (Int) -> Int {
    // 加操作 - 嵌套函數
    func stepForward(input:Int) -> Int {
        return input + 1;
    }
    // 減操作 - 嵌套函數
    func stepBackward(input:Int) -> Int {
        return input - 1;
    }
    
    return isBackwark ? stepBackward : stepForward;
}
// 即是接受'(Int) -> Int' 類型的函數
let moveNearerToZero = chooseStepFunction(currentInput > 0);
// 循環(huán)操作彩库,直到currentInput為0
while currentInput != 0 {
    print("currentInput: \(currentInput)");
    currentInput = moveNearerToZero(currentInput);
}
print("結束操作:\(currentInput)");
輸出結果:
currentInput: -5
currentInput: -4
currentInput: -3
currentInput: -2
currentInput: -1
結束操作:0


注:xcode7.3環(huán)境

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末肤无,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子侧巨,更是在濱河造成了極大的恐慌舅锄,老刑警劉巖鞭达,帶你破解...
    沈念sama閱讀 217,277評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件司忱,死亡現場離奇詭異皇忿,居然都是意外死亡,警方通過查閱死者的電腦和手機坦仍,發(fā)現死者居然都...
    沈念sama閱讀 92,689評論 3 393
  • 文/潘曉璐 我一進店門鳍烁,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人繁扎,你說我怎么就攤上這事幔荒。” “怎么了梳玫?”我有些...
    開封第一講書人閱讀 163,624評論 0 353
  • 文/不壞的土叔 我叫張陵爹梁,是天一觀的道長。 經常有香客問我提澎,道長姚垃,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,356評論 1 293
  • 正文 為了忘掉前任盼忌,我火速辦了婚禮积糯,結果婚禮上,老公的妹妹穿的比我還像新娘谦纱。我一直安慰自己看成,他們只是感情好,可當我...
    茶點故事閱讀 67,402評論 6 392
  • 文/花漫 我一把揭開白布跨嘉。 她就那樣靜靜地躺著川慌,像睡著了一般。 火紅的嫁衣襯著肌膚如雪祠乃。 梳的紋絲不亂的頭發(fā)上窘游,一...
    開封第一講書人閱讀 51,292評論 1 301
  • 那天,我揣著相機與錄音跳纳,去河邊找鬼忍饰。 笑死,一個胖子當著我的面吹牛寺庄,可吹牛的內容都是我干的艾蓝。 我是一名探鬼主播,決...
    沈念sama閱讀 40,135評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼斗塘,長吁一口氣:“原來是場噩夢啊……” “哼赢织!你這毒婦竟也來了?” 一聲冷哼從身側響起馍盟,我...
    開封第一講書人閱讀 38,992評論 0 275
  • 序言:老撾萬榮一對情侶失蹤于置,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后贞岭,有當地人在樹林里發(fā)現了一具尸體八毯,經...
    沈念sama閱讀 45,429評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡搓侄,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,636評論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現自己被綠了话速。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片讶踪。...
    茶點故事閱讀 39,785評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖泊交,靈堂內的尸體忽然破棺而出乳讥,到底是詐尸還是另有隱情,我是刑警寧澤廓俭,帶...
    沈念sama閱讀 35,492評論 5 345
  • 正文 年R本政府宣布云石,位于F島的核電站,受9級特大地震影響研乒,放射性物質發(fā)生泄漏留晚。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,092評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧瘦穆,春花似錦啊犬、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至隆判,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間僧界,已是汗流浹背侨嘀。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留捂襟,地道東北人咬腕。 一個月前我還...
    沈念sama閱讀 47,891評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像葬荷,于是被迫代替她去往敵國和親涨共。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,713評論 2 354

推薦閱讀更多精彩內容

  • 86.復合 Cases 共享相同代碼塊的多個switch 分支 分支可以合并, 寫在分支后用逗號分開宠漩。如果任何模式...
    無灃閱讀 1,366評論 1 5
  • SwiftDay011.MySwiftimport UIKitprintln("Hello Swift!")var...
    smile麗語閱讀 3,834評論 0 6
  • 函數是用來完成特定任務的獨立的代碼塊举反。給一個函數起一個合適的名字,用來標識函數做什么扒吁,并且當函數需要執(zhí)行的時候火鼻,這...
    窮人家的孩紙閱讀 811評論 2 1
  • Swift 介紹 簡介 Swift 語言由蘋果公司在 2014 年推出,用來撰寫 OS X 和 iOS 應用程序 ...
    大L君閱讀 3,211評論 3 25
  • importUIKit classViewController:UITabBarController{ enumD...
    明哥_Young閱讀 3,805評論 1 10