Swift學習(四):函數(定義,隱式返回,多返回值,參數標籤,默認參數值,可變參數,inout輸入輸出參數,函數重載,內聯函數,嵌套函數,typeslias)

函數的定義

func: 聲明這是一個函數

sum:函數名

(v1:  Int,  v2: Int): v1,v2是參數名, Int是參數類型

-> Int:返回值爲Int

sum(v1:  10, v2:  20):調用函數,調用函數時有參數名(v1, v2)必須帶着

形參默認是let,也只能是let

  • 無返回值的函數

->()表示返回值爲空,()實際上是一個空元組

-------------------------------------------------------------------------------------------------------------------------------

隱式返回

如果整個函數體是一個單一表達式,那麼函數會隱式返回這個表達式

-------------------------------------------------------------------------------------------------------------------------------

返回元組:實現多返回值

-------------------------------------------------------------------------------------------------------------------------------

函數的文檔註釋

       

參考:https://swift.org/documentation/api-design-guidelines/

-------------------------------------------------------------------------------------------------------------------------------

參數標籤(Argument Label)

  • 可以修改參數標籤

  • 可以使用下劃線加空格_ 省略參數標籤

-------------------------------------------------------------------------------------------------------------------------------

默認參數值(Deafault Parater Value)

  • 參數可以有默認值

  • C++的默認參數有個限制:必須從右往左設置。由於Swift擁有參數標籤,所以並沒有此類限制
  • 但是在省略參數標籤時需要特別注意:要傳入的沒有默認值的參數必須要設置參數標籤

-------------------------------------------------------------------------------------------------------------------------------

可變參數(Variadic Parameter)

Int...:表示一個或多個類型爲Int的參數

一個參數最多隻能有一個可變參數

緊跟在可變參數後面的參數不能省略參數標籤,否則會認爲是可變參數中的其中一個參數

-------------------------------------------------------------------------------------------------------------------------------

Swift自帶的print函數

-------------------------------------------------------------------------------------------------------------------------------

輸入輸出參數(In-Out Parameters)

注意:Swift屏蔽掉了一些東西,不能直接輸出地址,會報錯

Xcode進入彙編模式: DeBug --> Debug  Workflow --> Always Show Disassembly

下圖:callq(表示這是一個函數方法) 0x100000f60表示函數地址

lea:彙編裏的地址傳遞指令, 表示把0x10da加rip表示的地址傳遞給rdi,用%開頭的表示寄存器,也就是說rdi裏存的是地址值

(%rdi)表示根據rdi存儲的地址值找到相應的存儲空間

mov指令是賦值指令。

 

普通參數傳遞和inout參數地址傳遞彙編代碼對比:

/*
這是普通參數傳遞,明顯有mov賦值指令
 var number = 10
 
 func test(_ num: Int) {
 
 }
 
 test(number)
 
 0x100000f5e <+78>: movq   -0x30(%rbp), %rdi
 0x100000f62 <+82>: callq  0x100000f70               ; TestSwift.test(Swift.Int) -> () at main.swift:24
 
這是inout輸入輸出參數,沒有mov賦值指令,有lea地址指令
 var number = 10
 
 func test(_ num: inout Int) {
 
 }
 
 test(&number)
 
 0x100000f47 <+55>: leaq   0x10ca(%rip), %rdi        ; TestSwift.number : Swift.Int
 0x100000f4e <+62>: callq  0x100000f70               ; TestSwift.test(inout Swift.Int) -> () at main.swift:24
 */

 這裏說彙編是因爲要論證函數的輸入輸出參數(inout)是地址傳遞,並不是網上其他人說的先把參數傳給一箇中間值,然後把中間值當作返回值返回,然後賦值給外部參數,這裏涉及到彙編就不多說了。

  • 可以用inout定義一個輸入輸出參數:可以在函數內部修改外部實參的值,比如交換兩個數的值

也可以用元組

  • 可變參數不能標記爲inout
  • inout參數不能有默認值
  • inout參數的本質是地址傳遞(引用傳遞) 
  • inout參數只能傳入可以被多次賦值的(也就是需要用var,不能用let,更不能用40這種字面量)
  • 特別注意,大部分是引用傳遞,但是當傳遞給inout參數的是計算屬性,有監聽器的屬性等內容,其本質並非引用傳遞

-------------------------------------------------------------------------------------------------------------------------------

函數重載

  • 規則:
  1. 函數名相同
  2. 參數個數不同 || 參數類型不同 || 參數標籤不同

和第一個相比參數個數不同

和第一個相比參數類型不同

和第一個相比參數標籤不同

相應的輸出結果:

-------------------------------------------------------------------------------------------------------------------------------

函數重載注意點

  • 返回值類型與函數重載無關,即使不一樣也會報錯

 編譯器分不清該用哪個

  • 默認參數值和函數重載一起使用產生二義性,但是編譯器不會報錯(在C++中會報錯)

 默認使用第一個sum函數

  • 可變參數、省略參數標籤、函數重載一起使用產生二義性時,編譯器有可能會報錯

-------------------------------------------------------------------------------------------------------------------------------

內聯函數(Inline Function)

  • 如果開啓了編譯器優化(Release模式默認會開啓優化,Debug模式默認不開啓,需要手動調整),編譯器會自動將某些函數變爲內聯函數。
  • 將函數調用展開成函數體(比如將function test {print("A")} 直接轉化成print("A"),消除了函數體的調用,節省了內存開銷)

  • 哪些函數不會被內聯
  1. 函數體比較長
  2. 包含遞歸調用
  3. 包含動態派發
  • @inline

在Release模式下,編譯器已經開啓優化,會自動決定哪些函數需要內聯 ,因此沒必要使用@inline

-------------------------------------------------------------------------------------------------------------------------------

函數類型(Function Type)

  • 每個函數都是有類型的,函數類型由形式參數類型、返回值類型組成

 函數類型爲: () -> Void 或 () -> ()

  函數類型爲: (Int, Int) -> Int

  通過函數類型定義變量,調用時不需要參數標籤

  • 函數類型作爲函數參數

  • 函數類型作爲函數返回值

 其中forward(_ forward: Bool) -> (Int) ->Int 表示forward(_ forward: Bool)這個函數的返回值是一個函數類型,即(Int) ->Int,它表示一個參數爲Int,返回值也是Int類型的函數

返回值是函數類型的函數,叫做高階函數。

-------------------------------------------------------------------------------------------------------------------------------

typealias

  • typealias用來給類型起別名

typealias給元組起別名

typealias給函數類型起別名IntFn,將IntFn作爲參數類型和返回值類型

-------------------------------------------------------------------------------------------------------------------------------

嵌套函數(Nested Function)

  • 將函數定義在函數內部

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章