【Swift】基礎語法(3) —— 函數 、方法和閉包

函數

函數是用來完成特定任務的獨立的代碼塊。html

定義

定義函數使用關鍵字func,指定一個或多個輸入參數和一個返回值類型。格式以下:swift

func 方法名(參數1:參數類型1,參數2:參數類型2) -> 返回值類型
{
   // ……
   return ...
}
複製代碼

元組做爲函數返回值

能夠用元組(tuple)類型讓多個值做爲一個複合值從函數中返回。數組

若是不肯定返回的元組必定不爲nil,那麼能夠返回一個可選的元組類型,如:bash

func minMax(array: [Int]) -> (min: Int, max: 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 (currentMin, currentMax)
}
複製代碼

可選元組類型如(Int, Int)?與元組包含可選類型如(Int?, Int?)是不一樣的.可選的元組類型,整個元組是可選的,而不僅是元組中的每一個元素值。閉包

外部參數名

能夠在局部參數名前指定外部參數名,中間以空格分隔,外部參數名用於在函數調用時傳遞給函數的參數,如:ide

func pow(firstArg a: Int, secondArg b: Int) -> Int {
   var res = a
   for _ in 1..<b {
      res = res * a
   }
   print(res)
   return res
}
pow(firstArg:5, secondArg:3)
複製代碼

若是提供了外部參數名,那麼函數在被調用時,必須使用外部參數名,函數內部則可使用局部參數名。函數

可變參數

可變參數能夠接受零個或多個值。優化

可變參數經過在變量類型名後面加入(...)的方式來定義,如:ui

func vari<N>(members: N...){
    for i in members {
        print(i)
    }
}
vari(members: 4,3,5)
vari(members: 4.5, 3.1, 5.6)
vari(members: "Google", "Baidu", "Runoob")
複製代碼

函數類型做爲參數類型

函數類型由函數的參數類型和返回類型組成,能夠當作是一個特殊的類型。如 (Int, Int) -> Intspa

將函數做爲參數傳遞給另一個函數:

func sum(a: Int, b: Int) -> Int {
    return a + b
}
func another(addition: (Int, Int) -> Int, a: Int, b: Int) {
    print("輸出結果: \(addition(a, b))")
}
another(addition: sum, a: 10, b: 20)
複製代碼

函數類型做爲返回類型 及 函數嵌套

將函數做爲返回值將會獲得一個函數類型的值,能夠經過調用來獲取這個返回函數的返回值,如:

// 返回值的類型爲 () -> Int
func calcDecrement(forDecrement total: Int) -> () -> Int {
   var overallDecrement = 0
   // 函數內部能夠定義新的函數,即函數嵌套
   func decrementer() -> Int {
      overallDecrement -= total
      return overallDecrement
   }
   return decrementer
}
let decrem = calcDecrement(forDecrement: 30)
// 執行返回的函數,輸出值爲 -30
print(decrem())
複製代碼

方法

方法是與某些特定類型相關聯的函數,在OC中,只有類才能定義方。可是在Swift中,能夠將方法定義在類、結構體和枚舉上。

實例方法

實例方法是屬於某個特定類、結構體或者枚舉類型實例的方法。

實例方法提供如下方法:

  • 能夠訪問和修改實例屬性
  • 提供與實例目的相關的功能

實例方法要寫在它所屬的類型的先後大括號({})之間。

實例方法可以隱式訪問它所屬類型的全部的其餘實例方法和屬性。

實例方法只能被它所屬的類的某個特定實例調用。

實例方法不能脫離於現存的實例而被調用。

(相似於OC中的實例方法)

例如:

class calculations {
    let a: Int
    let b: Int
    let res: Int
    
    init(a: Int, b: Int) {
        //實例方法的某個參數名稱與實例屬性名稱相同的時,參數名稱優先,這時須要用self來區分參數名稱和屬性名稱
        self.a = a
        self.b = b
        res = a + b
        print("Self 內: \(res)")
    }
    
    func tot(c: Int) -> Int {
        return res - c
    }
    
    func result() {
        print("結果爲: \(tot(c: 20))")
    }
}

// 調用
let pri = calculations(a: 600, b: 300)
pri.result()
複製代碼

結構體

struct Teacher {
    var name = "lilei"
    var age = 0
    
    // 方法定義時加上了mutating關鍵字,容許修改屬性
    mutating func changeName() {
        name = "hanmeimei"
    }
}

// 調用
var teacher = Teacher()
print(teacher.name)   //lilei
teacher.changeName()
print(teacher.name)    //hanmeimei
複製代碼

枚舉

enum Color{
    case red
    case yellow
    case green
    
    // 方法定義時加上了mutating關鍵字,容許修改屬性
    mutating func changeColor() {
        switch self {
        case .red:
            self = .yellow
        case .yellow:
            self = .green
        case .green:
            self = .red
        }
    }
}

// 調用
var color = Color.red
print(color)    //red
color.changeColor()
print(color)    //yellow
複製代碼

類型(類)方法

類型方法能夠對應到OC中的類方法進行理解。

結構體和枚舉的類型方法,在方法的func關鍵字以前加上關鍵字static。

類的類型方法,在方法的func關鍵字以前加上關鍵字class,子類能夠重寫父類的實現方法。

例如:

class Student: NSObject {
    static var name = "hanmeimei"
    class func sayHI(name :String) {
        print("hello \(name),I am \(self.name)")
    }
}

// 調用
Student.sayHI(name: "lilei")
複製代碼

結構體

struct Teacher {
    static var name = "lilei"
    static func changeName() {
        name = "hanmeimei"
    }
}

// 調用
print(Teacher.name)     //lilei
Teacher.changeName()
print(Teacher.name)     //hanmeimei
複製代碼

閉包

閉包(Closures)是自包含的功能代碼塊,能夠在代碼中使用或者用來做爲參數傳值。 相似於OC中的代碼塊(blocks)。

Swift中的閉包相對於代碼塊有不少優化的地方:

一、根據上下文推斷參數和返回值類型

二、從單行表達式閉包中隱式返回(也就是閉包體只有一行代碼,能夠省略return)

三、可使用簡化參數名,如$0, $1(從0開始,表示第i個參數...)

四、提供了尾隨閉包語法(Trailing closure syntax)

語法

閉包的語法形式以下:

{(參數1:參數類型1,參數2:參數類型2...) -> 返回值類型 in
   ...//執行代碼
}
複製代碼

例:

let divide = {(val1: Int, val2: Int) -> Int in 
   return val1 / val2 
}
let result = divide(200, 20)
print (result)
複製代碼

閉包表達式

閉包表達式是一種利用簡潔語法構建內聯閉包的方式,例如:

OC中的數組排序sortedArrayUsingComparator:代碼以下:

[array sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
   // 排序代碼
}];
複製代碼

對應的,swift中也提供了sorted(by:)的方法,例如:

let names = ["AT", "AE", "D", "S", "BE"]

// 使用普通函數(或內嵌函數)提供排序功能,閉包函數類型需爲(String, String) -> Bool。
func backwards(s1: String, s2: String) -> Bool {
    return s1 > s2
}
var reversed = names.sorted(by: backwards)
複製代碼

參數名稱縮寫

能夠直接經過$0,$1,$2來順序調用閉包的參數,例如:

var reversed = names.sorted( by: { $0 > $1 } )
複製代碼

運算符函數

String類型定義了關於大於號>的字符串實現,其函數類型與sorted(by:)所傳的函數類型一致,所以能夠直接傳>做爲參數:

var reversed = names.sorted(by: >)
複製代碼

尾隨閉包

尾隨閉包是調用時書寫在函數括號以後的閉包表達式,它將其做爲最後一個參數傳入調用的方法中,例如:

// sorted()中沒有傳遞參數,{ $0 > $1 }閉包將做爲最後一個參數傳入sorted方法中
// 等同於names.sorted( by: { $0 > $1 } )
var reversed = names.sorted() { $0 > $1 }
複製代碼

捕獲值

閉包能夠在其定義的上下文中捕獲常量或變量。

即便定義這些常量和變量的原域已經不存在,閉包仍然能夠在閉包函數體內引用和修改這些值(有點相似於OC中的block,會捕獲上下文中有用到的對象)。

例如:

func makeIncrementor(forIncrement amount: Int) -> () -> Int {
    var runningTotal = 0
    func incrementor() -> Int {
        runningTotal += amount
        return runningTotal
    }
    return incrementor
}

// 返回的incrementByTen其實是函數 incrementor,它會捕獲變量runningTotal
let incrementByTen = makeIncrementor(forIncrement: 10)
// 執行時,runningTotal = 0,返回的值爲10
print(incrementByTen())
// 執行時,runningTotal = 10,返回的值爲20
print(incrementByTen())

// 閉包是引用類型, 即不管將其賦值給變量仍是常量,它的值都指向的是閉包的引用(能夠看作是方法的地址),所以兩個值會指向同一個閉包:
let alsoIncrementByTen = incrementByTen
// 執行時,runningTotal = 20,返回的值爲30
print(alsoIncrementByTen())
複製代碼

參考文章

Swift 函數

Swift 方法

Swift 閉包

相關文章
相關標籤/搜索