Swift函數
Swift函數包含參數類型和返回值類型
函數定義
Swift使用關鍵字func
定義函數。
函數定義時可以指定0個,一個或多個輸入參數和一個返回值類型。
函數的實參傳遞順序必須和形參相同,->
后定義返回值類型
func funcName(形參/ 空) -> returnType {
statement
...
return parameters
}
函數參數
Swift可以接收一個或多個參數,我們可以用元組(Tuple)向函數傳遞一個或多個參數。也可以創建無參函數。
元組作為函數返回值
元組(Tuple)與數組類似,但元組中的元素可以是任何類型,使用圓括號。
可以使用元組類型(Tuple)讓多個值作為一個復合值從函數中返回。如果不確定返回值是否非nil,可以返回可選的元組,例如(Int,Int)?
。可選元組類型(Int, Int)?與元組包含可選類型如(Int?, Int?)是不同的,前者整個元組是可選的,后者只是每個值是可選的。
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)
}
函數參數名稱
函數參數都有一個外部參數和一個局部參數名。局部參數名在函數實現的內部使用,外部參數名用于在函數調用時傳遞給函數的參數,可以在局部參數名前指定外部參數名,中間以空格分隔。如果提供了外部參數名,在調用函數時必須使用外部參數名。
func funcName(inputString str: String) -> String {
return str
}
可變參數
當傳入函數的參數數量不確定時,可以在變量類型后面假如...
來定義可變參數。
func vari<N>(members: N...){
for i in members {
print(i)
}
}
常量、變量、I/O參數
一般默認在函數中定義的參數都是常量參數,只可查詢使用,不能改變值。如果要什么變量參數可以在前面加上var
,這樣就可以改變參數的值,如func getName(var id:String)...
。函數一般是傳值,不是傳引用,此時參數值可以在函數內部中改變但是并不影響原來的值。如果要修改參數原來的值,可以把該參數定義為輸入輸出參數(In-Out Parameters),在參數前加inout
關鍵字,此時需要傳引用。一個輸入輸出參數有傳入函數的值,這個值被函數修改,然后傳出函數,替換原來的值。
func swapTwoInts(inout a: Int,inout b: Int){
let t = a
a = b
b = t
}
var x = 0,y = 100
print("x = \(x) ;y = \(y)")
swapTwoInts(&x, b:&y)
print("x = \(x) ;y = \(y)")
輸出結果:
x = 0 ;y = 100
x = 100 ;y = 0
函數類型
每種函數都有種特定的函數類型,由函數的參數類型和返回類型組成。函數可以定義任何參數及類型。如果具有同樣的參數類型和返回類型則為同一種函數類型。既然函數可以認為是一種類型,那我們可以將函數作為參數類型或返回類型使用。
func sum(a: Int, b: Int) -> Int {
return a + b
}
var addition: (Int, Int) -> Int = sum
print("輸出結果: \(addition(40, 89))")
func another(addition: (Int, Int) -> Int, a: Int, b: Int) {
print("輸出結果: \(addition(a, b))")
}
another(sum, a: 10, b: 20)
函數嵌套
函數嵌套指在函數內定義一個新的函數,外部的函數可以調用函數內定義的函數。
// 嵌套函數
func calcDecrement(forDecrement total: Int) -> () -> Int {
var overallDecrement = 0
func decrementer() -> Int {
overallDecrement -= total
return overallDecrement
}
return decrementer
}
calcDecrement(forDecrement: 20)()
Swift閉包
閉包(Closures)是自包含的功能代碼塊,可以在代碼中使用或用來作為參數傳值。
swift中的閉包與OC中的block和其他一些語言中的匿名函數比較類似。
全局函數和嵌套函數其實就是特殊的閉包。
閉包的形式
全局函數 | 嵌套函數 | 閉包表達式 |
---|---|---|
有名字但不能捕獲任何值。 | 有名字,也能捕獲封閉函數內的值。 | 無名閉包,使用輕量級語法,可以根據上下文環境捕獲值。 |
Swift中閉包的優化:
- 根據上下文推斷參數和返回值類型。
- 從單行表達式閉包中隱式返回(閉包只有一行代碼,可以省略return)。
- 可以使用簡化參數名,如$0,$1...(從0開始表示第i個參數)
- 提供了尾隨閉包語法
語法:
{(parameters) -> returnType in
statements
}
實例:
let divide = {(val1: Int, val2: Int) -> Int in
return val1 / val2
}
let result = divide(200, 20)
print (result)
閉包表達式
閉包表達式是一種利用簡潔語法構建內聯閉包的方式。
sort函數
Swift標準庫提供了sort排序函數,會根據您提供的用于排序的閉包函數將已知類型數組的值進行排序。排序完成會返回一個排序好的數組,原數組不會被更改。sort
函數需要提供兩個參數。
- 已知類型的數組。
- 閉包函數。該閉包函數需要傳入與數組元素類型相同的兩個值,并返回一個布爾值用來表明第一個值是否排在第二個值前面。
let names = ["AT", "AE", "D", "S", "BE"]
// 使用普通函數(或內嵌函數)提供排序功能,閉包函數類型需為(String, String) -> Bool。
func backwards(s1: String, s2: String) -> Bool {
return s1 > s2
}
var reversed = names.sort(backwards)
參數名稱縮寫
通過$0,$1,$2來順序調用閉包的參數。var reversed = names.sort({$0 > $1})
運算符函數
>
的定義public func ><T : Comparable>(lhs: T, rhs: T) -> Bool
Swift 的String類型定義了關于大于號 (>) 的字符串實現,其作為一個函數接受兩個String類型的參數并返回Bool類型的值。 而這正好與sort(_:)方法的第二個參數需要的函數類型相符合。 因此,您可以簡單地傳遞一個大于號,Swift可以自動推斷出您想使用大于號的字符串函數實現:var reversed = names.sort(>)
尾隨閉包
尾隨閉包是一個書寫在函數括號之后的閉包表達式,函數支持將其作為函數最后一個參數調用。
func someFunctionThatTakesAClosure(closure: () -> Void) {
// 函數體部分
}
// 以下是不使用尾隨閉包進行函數調用
someFunctionThatTakesAClosure({
// 閉包主體部分
})
// 以下是使用尾隨閉包進行函數調用
someFunctionThatTakesAClosure() {
// 閉包主體部分
}
實例: var reversed = names.sort() { $0 > $1 }
捕獲值和引用類型
閉包可以在其定義的上下文中捕獲常量或變量,存儲一份副本,即使定義這些常量和變量的原域已經不存在,閉包仍然可以在閉包函數體內引用和修改這些值。同時函數和閉包都是引用類型,無論將函數還是閉包賦值給一個常量還是變量,實際上都是將常量/變量的值設置為對應函數/閉包的引用。
func makeIncrementor(forIncrement amount: Int) -> () -> Int {
var runningTotal = 0
func incrementor() -> Int {
runningTotal += amount
return runningTotal
}
return incrementor
}
let incrementByTen = makeIncrementor(forIncrement: 10)
// 返回的值為10
incrementByTen()
// 返回的值為20
incrementByTen()
// 返回的值為30
incrementByTen()
// 返回的值為40
incrementByTen()
let alsoIncrementByTen = incrementByTen
// 返回的值也為50
print(alsoIncrementByTen())
Swift枚舉
枚舉也是一種數據類型,只是這種類型只包含自定義的特定數據,它是一組有共同特性的數據的集合。Swift使用關鍵字enum
來定義。
Swift枚舉功能為:
- 聲明在類中,可以通過實例化類來訪問他的值。
- 枚舉也可以定義構造函數來提供一個初始成員值;可以在原始的實現基礎上擴展功能。
- 可以遵守協議來提供標準功能。
語法:
enum enumname {
// 枚舉定義放在這里
}
實例:
// 定義枚舉
enum DaysofaWeek {
case Sunday
case Monday
case TUESDAY
case WEDNESDAY
case THURSDAY
case FRIDAY
case Saturday
}
var weekDay = DaysofaWeek.THURSDAY
weekDay = .THURSDAY // weekDay類型已知,可用.語法取值
當weekDay的類型已知時,再次為其賦值可以省略枚舉名。使用顯式類型的枚舉值可以讓代碼具有更好的可讀性。
枚舉中定義的值(如 Sunday,Monday,……和Saturday)是這個枚舉的成員值(或成員)。case關鍵詞表示一行新的成員值將被定義。
注意: 和 C 和 Objective-C 不同,Swift 的枚舉成員在被創建時不會被賦予一個默認的整型值。在上面的DaysofaWeek例子中,Sunday,Monday,……和Saturday不會隱式地賦值為0,1,……和6。相反,這些枚舉成員本身就有完備的值,這些值是已經明確定義好的DaysofaWeek類型。
相關值和原始值
枚舉可分為相關值和原始值
相關值 | 原始值 |
---|---|
不同數據類型 | 相同數據類型 |
實例: enum {10,0.8,"Hello"} | 實例: enum {10,35,50} |
值的創建基于常量或變量 | 預先填充的值 |
相關值是當你在創建一個基于枚舉成員的新常量或變量時才會被設置,并且每次當你這么做得時候,它的值可以是不同的。 | 原始值始終是相同的 |
相關值
以下實例中我們定義一個名為 Student 的枚舉類型,它可以是 Name 的一個相關值(Int,Int,Int,Int),或者是 Mark 的一個字符串類型(String)相關值。
enum Student{
case Name(String)
case Mark(Int,Int,Int)
}
var studDetails = Student.Name("Runoob")
var studMarks = Student.Mark(98,97,95)
switch studMarks {
case .Name(let studName):
print("學生的名字是: \(studName)。")
case .Mark(let Mark1, let Mark2, let Mark3):
print("學生的成績是: \(Mark1),\(Mark2),\(Mark3)。")
}
原始值
原始值可以是字符串、字符或者任意整型值或浮點型值。每個原始值在它的枚舉聲明中必須是唯一的。
當原始值為整型時,不需要顯示的為每個成員賦值。如果第一個沒有賦值,會默認為0。隱式賦值的值一次增1.
enum Month: Int {
case January = 1, February, March, April, May, June, July, August, September, October, November, December
}
let yearMonth = Month.May.rawValue
print("數字月份為: \(yearMonth)。")
Swift結構體
Swift結構體是構建代碼所用的一種通用且靈活的構造體,我們可以為結構體定義屬性(常量,變量)和添加方法,從而擴展結構體的功能。
與OC的不同點:
- 結構體不需要包含實現文件和接口
- 結構體允許我們創建一個單一文件,并且系統會自動生成面向其它代碼的外部接口。
結構體總是通過被復制的形式在代碼中傳遞,因此它的值是不可以修改的。
語法
struct NameStruct {
Definition 1
Definition 2
……
Definition N
}
我們可以通過結構體名來訪問結構體成員,實例化結構體使用let
關鍵字。結構體內使用成員屬性使用 self 關鍵字。
以下實例化通過結構體實例化時傳值并且克隆一個結構體:
struct MarksStruct {
var mark: Int
init(mark: Int) {
self.mark = mark
}
}
var aStruct = MarksStruct(mark: 98)
var bStruct = aStruct // aStruct 和 bStruct 是使用相同值的結構體!
bStruct.mark = 97
print(aStruct.mark) // 98
print(bStruct.mark) // 97
結構體的應用
在你的代碼中,你可以使用結構體來定義你的自定義數據類型。
結構體實例總是通過值傳遞來定義你的自定義數據類型。
按照通用的準則,當符合一條或多條以下條件時,請考慮構建結構體:
- 結構體的主要目的是用來封裝少量相關簡單數據值。
- 有理由預計一個結構體實例在賦值或傳遞時,封裝的數據將會被拷貝而不是被引用。
- 任何在結構體中儲存的值類型屬性,也將會被拷貝,而不是被引用。
- 結構體不需要去繼承另一個已存在類型的屬性或者行為。
舉例來說,以下情境中適合使用結構體:
- 幾何形狀的大小,封裝一個width屬性和height屬性,兩者均為Double類型。
- 一定范圍內的路徑,封裝一個start屬性和length屬性,兩者均為Int類型。
- 三維坐標系內一點,封裝x,y和z屬性,三者均為Double類型。
結構體實例是通過值傳遞而不是通過引用傳遞。
Swift類
Swift并不要求你為自定義類去創建獨立的接口和實現文件。只需要在一個單一的文件中定義一個類,系統會自動生成面向其它代碼的外部接口。
類和結構體的對比
共同點:
- 定義屬性用于存儲值
- 定義方法用于提供功能
- 定義附屬腳本用于訪問值
- 定義構造器用于生成初始化值
- 通過擴展以增加默認實現的功能
- 符合協議以對某類提供標準功能
與結構體相比,類還有如下的附加功能:
- 繼承允許一個類繼承另一個類的特征
- 類型轉換允許在運行時檢查和解釋一個類實例的類型
- 解構器允許一個類實例釋放任何其所被分配的資源
- 引用計數允許對一個類的多次引用
語法:
Class Classname {
Definition 1
Definition 2
……
Definition N
}
作為引用類型訪問類屬性
累的屬性可以通過.
來訪問,格式為實例化類名.屬性名
。
恒等運算符
因為類是引用類型,有可能有多個常量和變量在后臺同時引用某一個類實例。
為了能夠判定兩個常量或者變量是否引用同一個類實例,Swift內建了兩個恒等運算符。
恒等運算符 | 不恒等運算符 |
---|---|
運算符為:=== | 運算符為:!== |
如果兩個常量或者變量引用同一個類實例則返回 true | 如果兩個常量或者變量引用不同一個類實例則返回 true |
參考: