swift 函數.和匿名函數

函數

注意: 沒有定義返回類型的函數會返回特殊的值,叫 Void。它實際上是一個空的元組(tuple),沒有任何元素,能夠寫成()。
使用元組做爲返回參數,返回多個參數git

  func count(string: String) -> (vowels: Int, consonants: Int, others: 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)
}

外部參數名

外部參數名..是爲了調用該函數時讓其參數更爲有表現力,更爲通順,同時還保持了函數體是可讀的和有明確意圖的。讓別人閱讀整段代碼時更方便
當其餘人在第一次讀你的代碼,函數參數的意圖顯得不明顯時,考慮使用外部參數名。若是函數參數名的意圖是很明顯的,那就不須要定義外部參數名了數組

  func join(string s1: String, toString s2: String, withJoiner joiner: String) -> String {
      return s1 + joiner + s2
  }

  join(string: "hello", toString: "world", withJoiner: ", ")

若是你須要提供外部參數名,可是局部參數名已經定義好了,那麼你不須要寫兩次參數名。相反,只寫一次參數名,並用井號(#)做爲前綴就能夠了。這告訴 Swift 使用這個參數名做爲局部和外部參數名。閉包

  func containsCharacter(#string: String, #characterToFind: Character) -> Bool {
    for character in string {
        if character == characterToFind {
            return true
        }
    }
    return false
}

默認值

將帶有默認值的參數放在函數參數列表的最後。這樣能夠保證在函數調用時,非默認參數的順序是一致的,同時使得相同的函數在不一樣狀況下調用時顯得更爲清晰。
當你未給帶默認值的參數提供外部參數名時,Swift 會自動提供外部名字。此時外部參數名與局部名字是同樣的,就像你已經在局部參數名前寫了井號(#)同樣。函數

  func join(s1: String, s2: String, joiner: String = " ") -> String {
    return s1 + joiner + s2
}

  join("hello", "world", joiner: "-")
// returns "hello-world"

可變參數

一個可變參數(variadic parameter)能夠接受一個或多個值.傳入可變參數的值在函數體內當作這個類型的一個數組生命週期

  • 一個函數至多能有一個可變參數,並且它必須是參數表中最後的一個。這樣作是爲了不函數調用時出現歧義。
  • 若是函數有一個或多個帶默認值的參數,並且還有一個可變參數,那麼把可變參數放在參數表的最後。
func arithmeticMean(numbers: Double...) -> Double {
    var total: Double = 0
    for number in numbers {
        total += number
    }
    return total / Double(numbers.count)
}

常量參數和變量參數

函數參數默認是常量。試圖在函數體中更改參數值將會致使編譯錯誤。這意味着你不能錯誤地更改參數值
注意: 對變量參數所進行的修改在函數調用結束後便消失了,而且對於函數體外是不可見的。變量參數僅僅存在於函數調用的生命週期中。內存

func alignRight(var string: String, count: Int, pad: Character) -> String {
    let amountToPad = count - countElements(string)
    for _ in 1...amountToPad {
        string = pad + string
    }
    return string
}

//下面這樣會報錯
func test(a:String){
  a = "sssss";
}

In-Out參數

  • 定義一個輸入輸出參數時,在參數定義前加 inout 關鍵字
  • 輸入輸出參數不能有默認值,並且可變參數不能用 inout 標記。若是你用 inout 標記一個參數,這個參數不能被 var 或者 let 標記。
  • 當傳入的參數做爲輸入輸出參數時,須要在參數前加&符,表示這個值能夠被函數修改
  func swapTwoInts(inout a: Int, inout b: Int) {
    let temporaryA = a
    a = b
    b = temporaryA
}
var someInt = 3
var anotherInt = 107
swapTwoInts(&someInt, &anotherInt);// "someInt is now 107, and anotherInt is now 3」

函數類型

函數類型,可讓一個變量能夠成爲多個函數,同時能夠把函數當參數進行傳遞或者當作返回值rem

var mathFunction: (Int, Int) -> Int = addTwoInts

func printMathResult(mathFunction: (Int, Int) -> Int, a: Int, b: Int) {
    println("Result: \(mathFunction(a, b))")
}

func chooseStepFunction(backwards: Bool) -> (Int) -> Int {
    func stepForward(input: Int) -> Int { return input + 1 }
    func stepBackward(input: Int) -> Int { return input - 1 }
    return backwards ? stepBackward : stepForward
}

閉包

閉包能夠捕獲和存儲其所在上下文中任意常量和變量的引用。 這就是所謂的閉合幷包裹着這些常量和變量,俗稱閉包。Swift 會爲您管理在捕獲過程當中涉及到的全部內存操做。
閉包採起以下三種形式之一:
全局函數是一個有名字但不會捕獲任何值的閉包
嵌套函數是一個有名字並能夠捕獲其封閉函數域內值的閉包
閉包表達式是一個利用輕量級語法所寫的能夠捕獲其上下文中變量或常量值的匿名閉包

閉包表達式:input

  { (parameters) -> returnType in
      statements
  }

閉包特性一:利用上下文推斷參數和返回值類型

閉包做爲函數參數的話,因爲類型推斷...能夠省去閉包參數的類型和返回值閉string

  reversed = sorted(names, { (s1: String, s2: String) -> Bool in return s1 > s2 } )
  reversed = sorted(names, { s1, s2 in return s1 > s2 } )

閉包特性二:隱式返回單表達式閉包,即單表達式閉包能夠省略return關鍵字

包函數體內若是是單一表達式,還能夠省去return語句it

  reversed = sorted(names, { s1, s2 in s1 > s2 } )

閉包特性三:參數名稱縮寫

  • 1 當使用參數名稱縮寫的時候能夠省去in
  • 2 運算符函數(Operator Functions)起做用還能夠簡寫
reversed = sorted(names, { $0 > $1 } )
reversed = sorted(names, >)

閉包特性四:尾隨(Trailing)閉包語法

若是您須要將一個很長的閉包表達式做爲最後一個參數傳遞給函數,能夠使用尾隨閉包來加強函數的可讀性。 尾隨閉包是一個書寫在函數括號以後的閉包表達式,函數支持將其做爲最後一個參數調用。

let digitNames = [
    0: "Zero", 1: "One", 2: "Two",   3: "Three", 4: "Four",
    5: "Five", 6: "Six", 7: "Seven", 8: "Eight", 9: "Nine"
]
let numbers = [16, 58, 510]
let strings = numbers.map {
    (var number) -> String in
    var output = ""
    while number > 0 {
        output = digitNames[number % 10]! + output
        number /= 10
    }
    return output
}

捕獲值

閉包能夠在其定義的上下文中捕獲常量或變量。
即便定義這些常量和變量的原域已經不存在,閉包仍然能夠在閉包函數體內引用和修改這些值。

閉包是引用類型。可是注意,當一個嵌套函數內的函數做爲返回值的時候其實是建立了一個新的函數.

//全局函數
var str = "Hello, playground"
func test(a:String=""){
    println(str)
}
test();            //"Hello, playground"
str = "Hello";
test();            //"Hello"

//嵌套函數
func makeIncrementor(forIncrement amount: Int) -> () -> Int {
    var runningTotal = 0
    func incrementor() -> Int {
        runningTotal += amount   //runningTotal
        return runningTotal
    }
    return incrementor
}

let incrementByTen = makeIncrementor(forIncrement: 10)
incrementByTen()
// 返回的值爲10
incrementByTen()
// 返回的值爲20
incrementByTen()
// 返回的值爲30

//因爲是建立了一個新函數..因此會像下面顯示
let incrementBySeven = makeIncrementor(forIncrement: 7)
incrementBySeven()
// 返回的值爲7
incrementByTen()
// 返回的值爲40

//因爲是引用類型.因此
let alsoIncrementByTen = incrementByTen
alsoIncrementByTen()
// 返回的值爲50

注意: Swift 會決定捕獲引用仍是拷貝值。 您不須要標註amount或者runningTotal來聲明在嵌入的incrementor函數中的使用方式。 Swift 同時也處理runingTotal變量的內存管理操做,若是再也不被incrementor函數使用,則會被清除。

相關文章
相關標籤/搜索