標籤:靈活 編輯 nested tuple 底線 第一個 推斷 already 沒有
// 函數
// 函數是一段完成特定任務的獨立程式碼片段, 你可以通過給函數命名來標識某個函數的功能, 這個名字可以被用來在需要的時候‘調用‘這個函數來完成它的任務
// swift 統一的函數文法非常的靈活, 可以用來表示任何函數, 包括從簡單的沒有參數名字的 C 風格函數, 到複雜的帶局部的外部參數 OC 風格函數, 參數可以提供預設值, 以簡化函數調用, 參數也可以即當做傳入參數, 也當做傳出參數,也就是說, 一旦函數執行結束, 傳入的參數值會被修改
// 在 swift 中, 每個參數都有一個由函數的參數實值型別和傳回值類型組成的類型, 你可以把函數類型當做任何其它普通變數類型一樣處理,這樣就可以更簡單地把函數當做別的函數的參數,也可以從其它函數中返回函數, 函數的定義可以寫在其它函數的定義中,這樣可以在嵌套函數範圍內實現功能封裝.
// 函數的定義與調用
// 當你定義一個函數時, 你可以定義一個或多個有名字和類型的值, 作為函數的輸入, 稱為參數, 也可以定義某種類型的值作為函數執行結束時的輸出, 稱為傳回型別
// 每個函數有個函數名, 用來描述函數執行的任務, 要使用一個函數時, 用函數名來調用這個函數, 並傳給它匹配的輸入值(稱作 實參), 函數的實參必須與函數參數裡參數的順序一致
func greet(person: String) -> String{
let greeting = "hello," + person + "!"
return greeting
}
// 函數的定義, 以 func 作為首碼, 指定函數傳回型別時, 用返回箭頭 -> (一個連字號後面跟一個右角括弧) 後跟傳回型別的名稱方式來表示
// 該定義描述了函數的功能, 它期望接收什麼作為參數和執行結束時它返回的結果是什麼類型
print(greet(person: "ahhh"))
// 注意 : prient(_:separator:terminator:) 函數的第一個參數並沒有設定一個標籤, 而其它的參數因為有了預設值, 因此是可選的
func greenAgain(person: String) -> String{
return "hello," + person + "!"
}
print(greenAgain(person: "houdehcneg"))
// 函數的類型與傳回值
// 函數參數與傳回值在 swift 中非常的靈活, 你可以定義任何類型的函數, 包括從只帶一個未具名引數的簡單函數到複雜的帶有運算式參數名和不同參數選項的複雜函數
// 無參數函數
// 函數可以沒有參數,
func sayHelloWorld() -> String{
return "Hello,World!"
}
print(sayHelloWorld())
// 儘管這個函數沒有參數,但是定義中在函數名後還是需要一堆圓括弧, 當被調用時,也需要在函數名寫一對圓括弧
// 多參數函數
// 函數可以有多種輸入參數, 這些參數被包含在函數的括弧內, 以逗號分隔
func greet(person: String,alreadyGreeted: Bool) -> String{
if alreadyGreeted {
return greenAgain(person: person)
}else{
return greet(person: person)
}
}
print(greet(person: "timw", alreadyGreeted: true))
// 無傳回值函數
// 函數可以沒有傳回值, 下面是 greet(person:)函數的另一個版本,這個函數 直接列印一個 String值, 而不是返回它:
func greet2(person: String){
print(person)
}
// 因為這個函數不需要傳回值, 所以函數的定義中沒有返回箭頭 (->) 和傳回型別
// 注意 : 嚴格上來說, 雖然沒有傳回值被定義, greet(person:) 函數依然返回了值,沒有定義傳回值的函數會返回一個特殊的 Void 值, 它其實是一個空的元組, 沒有任何元素, 可以寫成 ()
// 注意 : 傳回值可以被忽略, 但是定義了有傳回值的函數必須返回一個值, 如果在函數定義底部沒有返回任何值, 將導致編輯錯誤
// 多重傳回值函數
// 你可以用元組 (tuple) 類型讓多個值作為一個複合值從函數中返回
func minMax(array: [Int]) ->(min: Int, max: Int){
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 (currentMin,currentMax)
}
let bounds = minMax(array: [8,-5,2,109,-21,71])
print("min is \(bounds.min) ,max is \(bounds.max)")
// 需要注意的是, 元組的成員不需要在元組從函數中返回,因為它們的名字已經在函數的傳回型別中指定了
// 可選元組傳回型別
// 如果函數返回的元群組類型有可能整個元組都 ‘沒有值‘, 你可以使用可選的 (optional) 元組傳回型別反映整個元組可以為 nil 的事實, 你可以通過在元群組類型的右括弧後放置一個問號來定義一個可選元組,例如 (Int,Int)?
// 注意 : 可選元群組類型如 (Int,Int)? 與元組包含可選類型如 (Int?,Int?)是不同的, 可選的元群組類型,整個元組是可選的, 而不是元組中的某個元素值
// 前面的例子 minMax(array:) 函數返回了一個包含兩個 Int 值的元組,但是函數不會對傳入的數組執行任何檢查,如果傳入的 Array 參數是一個空數組,會觸發執行階段錯誤,為了安全地處理這個空數組問題, 將 minMax(array:) 函數改寫成可選元組的傳回型別, 並且當數組為空白時返回 nil
func minMax2(array: [Int]) -> (min: Int,max:Int)?{
if array.isEmpty {
return nil
}else{
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 (currentMin, currentMax)
}
}
// 你可以用可選綁定來檢查 minMax2(array:) 函數返回的是一個存在的元組還是 nil
if let bounds2 = minMax2(array: [8, -6, 2, 109, 3, 71]) {
print("min is \(bounds.min) and max is \(bounds.max)")
}
// 函數參數標籤和參數名稱
// 每個函數參數都有一個參數標籤 以及 一個參數名稱, 參數標籤在調用函數的時候使用,調用的時候需要將函數的參數標籤寫在對應的參數前面, 參數名稱在函數的實現中使用 , 預設情況下,函數參數使用參數名稱作為衙門的參數標籤
// 所有的參數都必須有獨一無二的名字,
// 指定參數標籤
// 你可以在函數名稱前指定它的參數標籤, 中間已空格分割
func someFunction(argumentlabel arameterName: Int){
print(arameterName)
}
someFunction(argumentlabel: 5)
// 忽略參數標籤
// 如果你不希望某個參數添加一個標籤, 可以使用一個底線(_)來代替一個明確的參數標籤
func someFunction2(_ firstParameterName:Int, seconedParamerer:Int){
print(firstParameterName + seconedParamerer)
}
someFunction2(8, seconedParamerer: 8)
// 如果一個參數有一個標籤, 那麼在調用的時候必須使用標籤來標記這個參數
// 預設參數值
// 你可以在函數體中通過給參數賦值來任意一個函數的參數定義預設值 (Deafult Value), 當預設值被定義後,調用這個函數是可以忽略這個參數
func someFunction3(parameterWithoutDefault:Int,parameterWithDefault:Int = 12){
print(parameterWithDefault + parameterWithoutDefault)
}
someFunction3(parameterWithoutDefault: 8, parameterWithDefault: 8)
someFunction3(parameterWithoutDefault: 8)
// 將不帶有預設值的參數放在函數參數列表的最前面, 一般來說, 沒有預設值的參數更加的重要, 將不帶有預設值的參數放在最前面保證在函數調時,非預設參數的順序是一致的,同事也使得相同的函數在不同的情況下調用時顯得更為清晰
// 可變參數
// 一個可變參數 可以接受 0 個 或者多個值, 函數調用時,你可以用可變參數來指定函數參數可以被傳入的不確定數量的輸入值, 通過在變數類型後面加(...)的方式來定義可變參數
// 可變參數的傳入值在函數體中變為次類型的一個數組,
func arithmeticMean(_ numbers:Double...) -> Double{
var total: Double = 0
for number in numbers {
total += number
}
return total / Double(numbers.count)
}
print(arithmeticMean(45.4,78.5,96.2,151,151,2551,96.58))
// 注意 : 一個函數最多可以擁有一個可變參數
// 輸入輸出參數
// 函數參數預設是常量, 試圖在函數體中更改參數值將會導致編輯錯誤.這意味著你不能錯誤地更改參數值,如果你想要一個函數可以修改參數的值, 並且想要在這些修改函數調用結束後仍然存在,那麼就應該把這個參數定義為輸入輸出函數
// 定義一個輸入輸出函數時,在參數定義前加 inout 關鍵字, 一個 輸入輸出參數 有傳入函數的值,這個值被函數修改,然後被傳出函數,替換原來的值,
// 你只能傳遞變數給輸入輸出參數,你不能傳入常量或者字面量,因為這些量是不能被修改的,當傳入的參數作為輸入輸出參數時,需要在參數名前加 & 符, 表示這個值可以被函數修改
// 注意 : 輸入輸出參數不能有預設值, 而且可變參數不能用 inout 標記
func swapTwoInts(_ a: inout Int,_ b: inout Int){
let temporaryA = a
a = b
b = temporaryA
}
// 調用
var someInt = 3
var antherInt = 107
swapTwoInts(&someInt, &antherInt)
print("a is :\(someInt), b is :\(antherInt)")
// 從上面的例子中,我們可以看到 someInt 和 antherInt 的原始值在 swapTwoInts(_:_:) 函數中被修改,儘管它們的定義在函數體外
// 注意 : 輸入輸出參數和傳回值不一樣的,上面的swapTwoInts 函數並沒有定義任何傳回值,但仍然修改了 someInt 和 anotherInt 的值, 輸入輸出參數是函數對函數體外產生影響的另一種方式
// 函數類型
// 每個函數都有特定的函數類型, 函數的類型有函數的參數類型和傳回值類型組成
func addTwoInts(_ a: Int, _ b: Int) -> Int{
return a + b
}
func multiplyTwoInts(_ a: Int, _ b: Int) -> Int{
return a * b
}
// 這個例子中定義了兩個簡單的數學函數, addTwoInts 和 multiplyTwoInts, 這兩個函數都接收兩個 Int 值, 返回一個 Int 值,
// 這兩個函數的類型是 (Int,Int) -> Int,可以解讀為‘這個函數類型有兩個 Int 類型的參數並返回一個 Int 類型的傳回值
// 下面的一個例子,沒有參數,也沒有傳回值
func printHelloWorld(){
print("Hello,World!")
}
// 這個參數的類型是: () -> Void, 或者叫做‘沒有參數,並返回 void 類型的值‘
// 使用函數類型
// 在 swift 中,使用函數類型就像使用其他類型一樣, 例如, 你可以定義一個類型為函數的常量或變數, 並將適當的函數賦值給它
var mathFunction: (Int,Int) ->Int = addTwoInts(_:_:)
// 這段代碼可以理解為. 定義一個叫做mathFunction 的變數,類型是‘一個有兩個 Int 類型的參數 並返回每一個 Int 類型的值的函數‘, 並讓這個新變數指向 addTwoInts 函數
// mathFunction 和 addTwoInts 有同樣的類型, 所以這個賦值過程在 Swift 類型檢查(type-check)中是允許的
// 現在你可以用 mathFunction 來調用賦值的函數
print("Result: \(mathFunction(2,5))")
// 有相同匹配類型的不同函數可以被賦值給同一個變數, 就像非函數類型的變數一樣
mathFunction = multiplyTwoInts(_:_:)
print("Result: \(mathFunction(5,8))")
// 就像其他類型一樣,當賦值一個函數給常量或者變數時,你可以讓 swift 來推斷其函數類型
let antherMathFunction = addTwoInts
// antherMathFunction 被推斷為 (Int,Int) ->Int 類型
// 函數類型作為參數類型
// 你可以用 (Int, Int) -> Int 這樣的函數類型作為另一個函數的參數類型, 這樣你可以將函數的一部分實現留給函數的調用者來提供
func printMathResult(_ mathFunction: (Int, Int) -> Int, _ a: Int, _ b: Int){
print("Result: \(mathFunction(a,b))")
}
printMathResult(addTwoInts(_:_:), 8, 5)
// 這個例子定義了printMathResult(_:_:_:)函數, 它有三個參數, 第一個參數叫 mathFunction, 類型是 (Int, Int) -> Int, 你可以傳入任何這種類型的函數, 第二個和第三個參數叫做 a 和 b ,他們的類型是 Int, 這兩個值作為已給出的函數的輸入值
// 當 printMathResult(_:_:_:) 被調用時,它被傳入 addTwoInts 函數和整數 a 和 b ,它用傳入的 a 和 b 來調用 addTwoInts(_:_:), 並輸出結果
// printMathResult(_:_:_:) 函數的作用就是輸出另一個適當類型的數學函數的調用結果, 它不關心傳入函數是如何?的.只關心傳入的函數是不是一個正確的類型,這使得 printMathResult(_:_:_:) 能以一種型別安全 (type-safe)的方式將一部分功能轉給調用者實現
// 函數類型作為傳回型別
// 你可以用函數類型作為另一個函數的返貨類型, 你需要做的是返回箭頭 (->) 後寫一個完整的函數類型
// 下面的這個例子中定義了兩個簡單的函數, 這兩個函數的類型都是 (Int) -> Int
func stepForward(_ input: Int) -> Int{
return input + 1
}
func stepBackward(_ input: Int) -> Int{
return input - 1
}
// 下面的函數的傳回型別是 (Int) -> Int 類型的函數,
func chooseStepFunction(backward: Bool) -> (Int) -> Int{
return backward ? stepBackward(_:) : stepForward(_:)
}
// 你可以用 chooseStepFunction(backward:) 來擷取兩個函數其中的一個
var currentValue = 3
let moveNearerToZero = chooseStepFunction(backward: currentValue > 0)
print(moveNearerToZero(currentValue))
// 嵌套函數
// 到目前為止本章中你所見到的所有函數都叫做全域函數 (global functions), 它們定義在全域域中,你也可以把函數定義在別的函數體中, 稱作 嵌套函數(nested functions)
// 預設情況下,嵌套函數是對外界不可見的, 但是可以被它們的外圍函數 (enclosing function) 調用, 一個外圍函數也可以返回它的某一個嵌套函數, 使得這個函數可以在其他域中被使用
// 你可以用返回嵌套函數的方式重寫 chooseStepFunction(backward:)函數
func chooseStepFunction2(backward: Bool) -> (Int) -> Int {
func stepForward(input: Int) -> Int { return input + 1 }
func stepBackward(input: Int) -> Int { return input - 1 }
return backward ? stepBackward : stepForward
}
var currentValue2 = -4
let moveNearerToZero2 = chooseStepFunction(backward: currentValue > 0)
print(moveNearerToZero2(currentValue2))
Swift 學習- 07 -- 函數