Swift學習筆記 - 函數與閉包

來源:互聯網
上載者:User

標籤:

import Foundation

//1.函數的定義與調用
//以 func 作為首碼,返回箭頭 -> 表示函數的傳回型別
func sayHello(name: String) -> String {
let greeting = "Hello " + name + "!"
return greeting
}

println(sayHello("Anna"))

 

//1.1函數的參數與傳回值
//函數可以有多個輸入參數,寫在圓括弧中,用逗號分隔
func minusResult(start: Int, end: Int) -> Int{
return end - start
}

println(minusResult(1, 10))

//1.2無參函數
func sayHelloWorld() -> String {
return "hello world"
}
println(sayHelloWorld())


//1.3無傳回值函數
/*
嚴格上來說,雖然沒有定義傳回值,sayGoodbye 函數依然返回了值。
沒有定義傳回型別的函數會返回特殊的值,叫 Void。它其實是一個空的元組(tuple),沒有任何元素,可以寫成()。
*/
func sayGoodbye(name: String) {
println("Goodbye, \(name)" )
}
println(sayGoodbye("Dave"))


//1.4多重傳回值函數
//你可以用元組(tuple)類型讓多個值作為一個複合值從函數中返回
func count(string : String) -> (vs: Int, cs: Int, os: Int) {
var vowels = 0, consonants = 0, others = 0
for character in string {
switch String(character).lowercaseString {
case "a", "e", "i", "o", "u":
++vowels
case "b", "c", "d", "f", "g", "h", "j", "k", "l", "m",
"n", "p", "q", "r", "s", "t", "v", "w", "x", "y", "z":
++consonants
default:
++others
}
}

return (vowels, consonants, others)
}
let total = count("some arbitrary string!")
println("\(total.vs) vowels and \(total.cs) consonants")


//2 函數參數名
//2.1 外部參數名

//Demo:把兩個字串聯在一起,示範使用外部參數的好處
/*
//不使用外部參數
func join(s1: String, s2: String, joiner: String) -> String {
return s1 + joiner + s2
}
println(join("hello", "world", ", ")) //這三個字串的用途不是很明確
*/

/*
//使用外部參數名稱
//為了讓這些字串的用途更為明顯,我們為 join 函數添加外部參數名
func join(string s1: String, toString s2: String, withJoiner joiner: String) -> String {
return s1 + joiner + s2
}
//使用外部參數名更有表現力,更為通順,同時還保持了函數體是可讀的和有明確意圖的
println(join(string: "hello", toString: "world", withJoiner : ", "))
*/


//2.2 簡寫外部參數名
//如果你需要提供外部參數名,但是局部參數名已經定義好了,那麼你不需要寫兩次這些參數名。相反,唯寫一次參數名,並用井號(#)作為首碼就可以了。這告訴 Swift 使用這個參數名作為局部和外部參數名。
func containsCharacter(#string: String, #characterToFind: Character) -> Bool {
for character in string {
if character == characterToFind {
return true
}
}

return false
}

//這樣定義參數名,使得函數體更為可讀,清晰,同時也可以以一個不含糊的方式被調用
let containsAVee = containsCharacter(string: "qwertyuiop", characterToFind: "y")
println(containsAVee)


//2.3 預設參數值
//你可以在函數體中為每個參數定義預設值。當預設值被定義後,調用這個函數時可以略去這個參數
func join(string s1: String, toString s2: String, withJoiner joiner: String = ", ") -> String {
return s1 + joiner + s2
}
let str1 = join(string: "hello", toString: "world", withJoiner: "-") //指定第三個參數
println(str1)

let str2 = join(string: "hello", toString: "world") //不指定第三個參數, 第三個參數將使用預設值
println(str2)

//2.4 預設值參數的外部參數名
//當你未給 帶預設值的參數提供外部參數名時,Swift 會自動提供外部名字。此時外部參數名與局部名字是一樣的,就像你已經在局部參數名前寫了井號(#)一樣
func join(s1: String, s2: String, joiner: String = " ") -> String {
return s1 + joiner + s2
}
let str3 = join("hello", "world", joiner: "-")
println(str3)


//3.可變參數
//傳入可變參數的值在函數體內當做這個類型的一個數組。例如,一個叫做 numbers 的 Double... 型可變參數,在函數體內可以當做一個叫 numbers 的 Double[] 型的常數陣列。
//一個函數最多能有一個可變參數
//可變參數必須放在參數表中最後的位置
func aritheticMean(numbers: Double...) -> Double {
var total: Double = 0
for number in numbers {
total += number
}
return total / Double(numbers.count)
}
println(aritheticMean(1.2, 3.5, 4.6))
println(aritheticMean(1.2, 3.5, 4.6, 9.0, 10.0))

 

//4 常量參數與變數參數
//函數參數預設是常量。但是有時候,如果函數中傳入的參數可以修改的話將很有用。你可以通過指定一個或多個參數為變數參數,從而避免自己在函數中定義新的變數。變數參數不是常量,你可以在函數中把它當做新的可修改副本來使用。
//通過在參數名前加關鍵字 var 來定義變數參數
func alignRight(var string: String, count: Int, pad: Character) -> String {
let amountToPad = count - countElements(string)
for _ in 1...amountToPad {
string = pad + string
}
return string
}

let originalString = "hello"
let paddedString = alignRight(originalString, 10, "-")
println("originalString:" + originalString)
println("paddedString:" + paddedString)

 


//5 輸入輸出參數
//變數參數,正如上面所述,僅僅能在函數體內被更改。如果你想要一個函數可以修改參數的值,並且想要 這些修改在函數調用結束後仍然存在,那麼就應該把這個參數定義為輸入輸出參數(In-Out Parameters)。

//定義一個輸入輸出參數,在參數的前面加 inout關鍵字
//輸入輸出參數不能有預設值,而且可變參數不能用 inout 標記。如果你用 inout 標記一個參數,這個參數不能被 var 或者 let 標記。
func swapTwoInts(inout a: Int, inout b:Int) {
let temp = a
a = b
b = temp
}

//只能傳入一個變數作為輸入輸出參數
var someInt = 3
var anotherInt = 7
//當傳入的參數作為輸入輸出參數時,需要在參數的前面加&,表示這個值可以被函數修改
swapTwoInts(&someInt, &anotherInt)
println("someInt is now \(someInt), and anotherInt is now \(anotherInt)")

 


//6.函數類型 (是一種資料類型, 類似C語言的函數指標, OC語言的Block)
//分三步: 1.定義函數; 2.聲明函數類型變數或常量; 3.給函數類型變數賦值
//1.定義函數
func addTwoInts(a: Int, b: Int) -> Int {
return a + b
}

func sum(a: Int, b: Int) -> Int {
return a - b
}

func printHelloWorld()
{
println("hello, world")
}

/*
//2、聲明一個叫做 mathFunction 的變數,類型是‘一個有兩個 Int 型的參數並返回一個 Int 型的值的函數‘
var mathFunction: (Int, Int) -> Int

//3.給函數類型變數賦值
mathFunction = addTwoInts


//既然是變數, 我們可以重新給mathFunction賦值
mathFunction = sum
*/

/*
//2 3步合并
var mathFunction: (Int, Int) -> Int = sum
*/

//類型推導, 可以讓Swift來推測 mathFunction 的類型
var mathFunction = sum
//mathFunction = printHelloWorld //錯誤, 類型不符


//4.使用
println("Result: \(mathFunction(2, 3))")

 

//Swift調用C函數
desc1()

//Swift調用OC
var funcClass = FuncBlock() //拿到OC類對象
funcClass.desc2()

 


//6.1 函數類型作為參數類型
func printMathResult(mathFun: (Int, Int) -> Int, a: Int, b: Int){
println("Result: \(mathFun(a, b))")
}
printMathResult(addTwoInts, 4, 7)


/*
//6.2 函數類型作為傳回型別
func stepForward(input: Int) -> Int {
return input + 1
}
func stepBackward(input: Int) -> Int {
println("stepBackward")
return input - 1
}

//好,有沒有暈???暈了就休息一下,再看一遍剛剛講過的內容;沒暈就繼續了
func chooseStepFunction(backwards: Bool) -> (Int) -> Int {
return backwards ? stepBackward : stepForward //返回函數類型
}
var currentValue = 3
let moveNearerTozero = chooseStepFunction(currentValue > 0)
//let moveNearerTozero:(Int) -> Int = chooseStepFunction(true) //原型
//moveNearerTozero = stepBackward
println("moveNearerTozero:\(moveNearerTozero)") //moveNearerTozero指向stepBackward

println("Result:\(moveNearerTozero(10))")
*/

//嵌套函數
func chooseStepFunction(backwards: Bool) -> (Int) -> Int {
func stepForward(input: Int) -> Int {
return input + 1
}
func stepBackward(input: Int) -> Int {
println("stepBackward")
return input - 1
}
return backwards ? stepBackward : stepForward //返回函數類型
}
var currentValue = -4
let moveNearerTozero = chooseStepFunction(currentValue > 0)
println("嵌套函數: \(moveNearerTozero(10))")

 

 


//8.閉包
//8.1閉包運算式

let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]


//不使用閉包
func backwards(s1: String, s2: String) -> Bool {
return s1 > s2
}
//Swift 標準庫提供了sort函數,會根據您提供的基於輸出類型排序的閉包函數將已知類型數組中的值進行排序。
var reversed = sort(names, backwards)
println(reversed)


//使用閉包
//閉包的函數體部分由關鍵字in引入。 該關鍵字表示閉包的參數和傳回值類型定義已經完成,閉包函數體即將開始。
reversed = sort(names, {(s1: String, s2: String) -> Bool in
return s1 > s2
})

//根據上下文推斷類型
reversed = sort(names, {s1, s2 in return s1 > s2})


//8.2單運算式閉包隱式返回
//如果閉包體只有一個運算式, 那麼return關鍵字可以省略
reversed = sort(names, {s1, s2 in s1 > s2})

//8.3 參數名稱縮寫
//$0和$1表示閉包中第一個和第二個String類型的參數。
reversed = sort(names, {$0 > $1})

//8.4 運算子函數
//Swift 的String類型定義了關於大於符號 (>) 的字串實現
reversed = sort(names, >)


//8.5 尾隨閉包
//如果您需要將一個很長的閉包運算式(以至於不能在一行中進行書寫時)作為最後一個參數傳遞給函數,可以使用尾隨閉包來增強函數的可讀性。 尾隨閉包是一個書寫在函數括弧之後的閉包運算式,函數支援將其作為最後一個參數調用。
reversed = sort(names){$0 > $1}

println(reversed)

 

//8.6 捕獲值
func makeIncrementor(forIncrement amount: Int) -> ()->Int {
var runningTotal = 0

//incrementor函數並沒有擷取任何參數,但是在函數體內訪問了runningTotal和amount變數。這是因為其通過捕獲在包含它的函數體內已經存在的runningTotal和amount變數而實現
func incrementor() -> Int {
runningTotal += amount
return runningTotal
}

return incrementor
}
let incrementByTen = makeIncrementor(forIncrement: 10)

//因為每次調用該函數的時候都會修改runningTotal的值,incrementor捕獲了當前runningTotal變數的引用,而不是僅僅複製該變數的初始值。捕獲一個引用保證了當makeIncrementor結束時候並不會消失,也保證了當下一次執行incrementor函數時,runningTotal可以繼續增加
println(incrementByTen()) //10
println(incrementByTen()) //20
println(incrementByTen()) //30


let incrementBySeven = makeIncrementor(forIncrement: 7)
println(incrementBySeven()) //7
println(incrementByTen()) //40


//8.7 閉包是參考型別
//上面的例子中,incrementBySeven和incrementByTen是常量,但是這些常量指向的閉包仍然可以增加其捕獲的變數值。 這是因為函數和閉包都是參考型別。

//如果將閉包賦值給了兩個不同的常量/變數,兩個值都會指向同一個閉包,指向的都是 incrementor
let alsoIncrementByTen = incrementByTen
println(alsoIncrementByTen()) //50

 

Swift學習筆記 - 函數與閉包

相關文章

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.