從 函數 到 Swift

函數是一段完成某個事務的代碼片斷數組

定義

func 函數名(參數列表) -> 返回值類型 {
    // :TODO
    return or not 
}

* 函數的參數能夠省略,可是包裹着參數的 () 不能夠省略
* 返回值爲 -> void 的時候,意味着無返回值,-> void 也能夠省略
* 本質來講,函數和方法是同一種東西,只不過方法是定義在函數內部的函數,咱們稱之爲方法
複製代碼

類型

參數的有無返回值的有無 能夠組成4種基本狀況bash

1.無參無返函數

好比:咱們想寫一個函數 打印字符串 "helloworld"

* Void v是大寫

func printAction() -> Void {
    print("helloworld")
}

上面這段代碼無返回值,沒有return操做,能夠省略 -> Void,等價於

func printAction() {
    print("helloworld")
}

printAction() 
/// helloworld
複製代碼

2.無參有返post

// 沒有參數,返回值的類型 是 字符串String

func printAction() -> String {
    return "Swift"
}

var str = printAction()  // 接收返回值

print("\(str) 是最好的語言")
/// Swift 是最好的語言
複製代碼

3.有參有返ui

// 傳入 2個 Int 類型的參數,返回值也是 Int 類型

func printAction(num1: Int,num2: Int) -> Int {
    return num1 + num2
}

printAction(num1: 2, num2: 3)
/// 5
複製代碼

4.有參無返spa

// 傳入一個 String 類型的參數,沒有返回值

func printAction(s1: String) {
     print(s1) 
}

printAction(s1: "Swift is ok")
/// Swift is ok
複製代碼

5.隱式返回

# 🐷:當函數 執行語句中的表達式 是 單一表達式的時候,咱們能夠省略return 字段

func printAction(num1: Int,num2: Int) -> Int {
    return num1 + num2
}

上面函數等價於
func printAction(num1: Int,num2: Int) -> Int {
    num1 + num2
}

複製代碼

6.多重返回指針

如今咱們想作這樣一件事,定義一個函數,傳入一個數組,返回2個值,一個最大,一個最小

func printAction(array: [Int]) -> (min: Int, max: Int) {
    // 取出數組第一個,同時賦值給 當前最小值,最大值
    var curMin = array[0] 
    var curMax = array[0]
    
    // 從第二個開始遍歷,也就是下標1
    for item in array[1..<array.count] {
        if item < curMin {
            curMin = item
        } else if item > curMax {
            curMax = item
        }
    }
    return (curMin, curMax)
}

print(printAction(array: [1,2,3,4,5]))
/// (min: 1, max: 5)
複製代碼

7.可選返回類型

若是說上面的案例咱們傳入的數組是空呢?那麼在 訪問array[0] 的時候就會發生 運行時錯誤code

因此咱們須要 定義 返回值爲可選型,假如傳入的數組爲空時,咱們返回nil事務

func printAction(array: [Int]) -> (min: Int, max: Int)? {
    // 這裏咱們首先判斷是否爲空,爲空返回nil
    if array.isEmpty {
        return nil
    }
    
    var curMin = array[0]
    var curMax = array[0]
    for item in array[1..<array.count] {
        if item < curMin {
            curMin = item
        } else if item > curMax {
            curMax = item
        }
    }
    return (curMin, curMax)
}

# 既然返回值是可選型,那麼咱們取值的時候就要注意了

* 返回值類型是 元祖,咱們能夠定義一個元祖去接收
* 若是元祖有值,咱們能夠進if,反之進else

var tuples = printAction(array: [])

if let result = tuples {
    print(result.0,result.1)
} else {
    print("我是空的")
}
複製代碼

可選綁定 if let 介紹內存

函數的標籤以及參數

每一個函數都包含 參數標籤參數名稱,而 參數標籤大大增長了代碼的可讀性

func someFuction(參數標籤 參數名稱: 參數類型) {
    // do something
    ...
    // 參數標籤 和  參數名稱 以 空格分隔
    // 參數標籤能夠省略
}
複製代碼

好比說

func eatFuction(food: String, who:String) {
    print("今天和\(who) 吃了\(food)")
}

eatFuction(food: "麻辣燙", who: "表弟")

// 這樣的調用 若是不明白函數內部實現的人,實際上是懵逼的
// foot 和 who 有什麼聯繫?
// 麻辣燙是表弟作的嗎?

* 若是加上參數標籤呢?

func eatFuction(eat food: String, with who:String) {
    print("今天和\(who) 吃了\(food)")
}

那麼的調用就是這樣

eatFuction(eat: "kfc", with: "表弟")
// 今天和表弟一塊兒吃了kfc
// 有沒有一種豁然開朗的感受,沒錯 是我帶他吃的
複製代碼

省略參數標籤 _

若是咱們想省略一些參數,咱們並不想知道 參數表明的含義,可使用下劃線 _來操做

並不關心這個參數 好比:

func eatFuction(_ food: String, _ who:String) {
    print("今天和\(who) 吃了\(food)")
}

eatFuction("飯", "別人")

// 今天和別人吃了飯,我管你是誰
複製代碼

默認參數

函數的參數中咱們是能夠添加默認值的,用來表達一些默認的值,也許不會修改 好比 去圖書館看書

# 含有默認值的參數列表,函數默認會提供2個初始化構造方法
# 一個包含默認值能夠改,一個不包含默認值

func defuleFuction(whichPlace: String, todo: String = "讀書") {
    print("我天天都去\(whichPlace) \(todo)")
}

defuleFuction(whichPlace: "圖書館")

// 我天天都是圖書館看書
// 我只要寫地點,不須要寫幹什麼

* 假如我想更改這個默認值,

defuleFuction(whichPlace: "圖書館",todo: "看妹子")
// 那麼我也能夠去圖書館 看妹子呀
複製代碼

可變參數

可變參數 顧名思義就是 參數是可變的,當咱們不肯定參數值的數量時,能夠用 省略號... 來表示這個參數是可變的

// 咱們定義一個函數,累加咱們傳入的數值

func variableFuction(_ varialbeStrings: Int...,num: Int) -> Int {
    var total = 0
    for item in varialbeStrings {
        total += item
    }
    return total + num
}
print(variableFuction(1,2, num: 3))

// 能夠看到 我把可變參數寫在了第一個參數,這樣是不建議的

# 注意
* 一個函數最多隻能擁有一個可變參數
* 有可變參數的時候 ,最好寫在後面,易讀
* 有可變參數的時候,另外的參數不能夠省略名稱

也就是說我這麼寫 是錯誤的 ❌
func variableFuction(_ varialbeStrings: Int...,_: Int) -> Int {
// 省略了num 報錯
複製代碼

輸入輸出參數 inout

這2段代碼咱們來看一下

// 傳入一個Int 分別加 1,而後返回

✅
func addFuction(num: Int) -> Int {
    return num + 1
}

❌
func addOtherFuction(num: Int) -> Int {
    num += 1
    return num
}

# 🐷
# 事實上Swift 會默認認爲 全部可能的地方 都是 不可變的,畢竟是靜態語言
# 因此 函數的聲明中,參數默認都是 let 修飾的

第一種方法裏,num +1 ,至關於咱們建立了一個臨時變量
var temp = num + 1,咱們改變的是temp 的值

而第二種方法,咱們是在改變num 自身的值,這是不被容許的

那麼咱們顯示調用var ?

func addOtherFuction(var num: Int) -> Int {
    num += 1
    return num
}
# error: 'var' as a parameter attribute is not allowed,也是不能夠的
複製代碼

# 因此咱們引入了 inout,輸入輸出函數

默認狀況下,函數的參數傳遞是值傳遞,由於Int 是值類型 若是想改變函數外面的變量,則須要傳遞變量的地址

也就是 說 inout 的本質 是 引用傳遞,將變量 的指針 經過& 符號 捕獲,而且修改指針指向的內存 裏的值

func addOtherFuction( num: inout Int) -> Int {
    num += 1
    return num
}

var num1 = 9
var num2 = addOtherFuction(num: &num1)

print(num1)
print(num2)
// num1 num2 都是10

# 必需要用 & 符號,相似c語言的取值符,但實際應該更爲複雜
複製代碼

函數類型

每一個函數 都有本身的函數類型,它的函數類型 是由 參數類型返回值類型 共同決定的

咱們能夠視這個類型爲一個總體

好比

func printAction(num1: Int,num2: Int) -> Int {
    return num1 + num2
}

它的函數類型就是 (Int, Int) -> Int
複製代碼

函數類型做爲參數

這裏定義了一個addFuction,傳入2個數,相加並返回

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

// 函數類型是 (Int, Int) -> Int
// 咱們把 上面的函數做爲參數 給到新的 函數

func newAddFuction(_ addName: (Int, Int) -> Int, a: Int, b: Int) {
    print(addName(a,b))
}

能夠看到 addFuction這個參數 就是   (Int, Int) -> Int 類型的
那麼咱們調用的時候 ,是否是就能夠把 第一個函數  addFuction 傳給 newAddFuction

newAddFuction(addFuction, a: 2, b: 3)

# 咱們也能夠定義一個類型 指向這個類型 
# 好比 var mathFunction: (Int, Int) -> Int = addFuction
那麼 newAddFuction 也能夠寫爲:

func newAddFuction(_ addName: (Int, Int) -> Int, a: Int, b: Int) {
   print(addName(a,b))
}

newAddFuction(tempFunction, a: 2, b: 3)
複製代碼

函數類型做返回值

把參數類型 在函數體內 當作一個總體 返回

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

// 經過getAddFuction  拿到 addFuction
// 由於返回值類型 和  addFuction 類型同樣 都是  (Int, Int) -> Int

func getAddFuction() -> (Int, Int) -> Int {
    return addFuction
}

let newAction = getAddFuction()

print(newAction(3,4))
複製代碼

後續還會在補充 還請多多指點

謝謝

相關文章
相關標籤/搜索