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