Swift學習筆記6——函數(Function)

Swift的函數和C的函數定義方式有些區別,它是將返回類型寫在函數的最後。一般定義函數的語法如下

func函數名 (參數列表) -> 返回值 {

       //函數體

}

舉一個例子,這個函數輸入一個字符串,然後打印出這個字符串,並且返回一個字符串。

//函數定義
func printYourName (name: String)->String {
    print(name)
    return "Hello, " + name
}

var s = printYourName("Tom")   //函數調用
print(s)    //打印 Hello, Tom


如果一個函數沒有返回值,那麼從  -> 返回值  這個部分可以省略。比如下面例子

//函數定義
func printYourName (name: String) {
    print(name)
}

再來看看有多個參數的情況,比如下面例子。

func printTwoString(firstString: String, secondString: String) {
    print(firstString,secondString)
}
printTwoString("hello", secondString: "Kate")

        先了解一個概念,在函數定義時候,參數列表中使用的fristString和secondString稱爲局部參數名(local parameter name)。所謂的局部參數名,就是在函數內部所使用的名字。

        注意到在調用這個函數的時候,第二參數前面加上了secondString。雖然和局部參數名一樣,但這裏稱爲外部參數名。因爲Swift在默認情況下,外部參數名和內部參數名一樣。而且在默認情況下,調用函數時忽略第一個參數的外部參數名,所以在調用的時候不用加上fristString   。如果想要把第二參數的外部參數名也忽略的話,那麼在定義函數的時候在局部參數名前面加上 _ ,並用空格分隔就行。如下,

func printTwoString(firstString: String, _ secondString: String) {
    print(firstString,secondString)
}
printTwoString("hello",  "Kate")  //忽略了第二參數的外部參數名之後,這裏就不能加上外部參數名了

         當然,可以自己定義外部參數名,例子如下。

func printTwoString(say firstString: String, to secondString: String) {
    print(firstString,secondString)
}
printTwoString(say:"hello", to: "Kate")   //定義了外部參數名之後,調用的時候必須加上外部參數名

         此外,還可以給參數賦值默認值。官方文檔建議我們把帶默認值的參數放在參數列表的末尾,這樣在調用的時候不至於混淆。但是其實可以對每個參數都賦值默認值。比如下面的例子。

func printTwoString( firstString: String = "hello", secondString: String = "Lucy", thirdString: String = "end") {
    print(firstString,secondString,thirdString)
}
printTwoString( secondString:"two")  //使用外部參數名指定要賦值的參數,其他參數使用默認值,輸出 hello two end

值得注意的是,如果沒有默認值的參數在調用的時候也沒有給其賦值,那麼會在編譯的時候報錯。

如果你又把參數列表的外部參數名都去掉的話,那麼在調用的時候,你給的參數將會從頭開始匹配。如果參數類型不匹配的話,就會報錯。當然,不建議大家這樣做,因爲會導致程序的可讀性變差。


可變參數列表

func printStrings(strings: String...) {
    print(strings)
}

printStrings("1","2","3")  //輸出 ["1", "2", "3"]
通過輸出我們可以看到,可變參數在函數體內是以數組的類型存在的。這點在官方文檔上有說明。


常量和變量參數

在默認的情況下,參數傳遞給函數後都是常量,也就是說不能在函數體裏面對參數進行修改。

func add(first: Int, _ second: Int) -> Int{
    first = 2;  //這句報錯
    return first + second
}



如果要修改參數,必須在參數列表裏面加上 var

func add(var first: Int, _ second: Int) -> Int{
    first = 2;
    return first + second
}

但是參數默認是值傳遞,如果我們調用add函數

var f = 1;
var s = 2;
let result = add(f,s)
print(f) //f仍然是1

如果想要對形參的修改影響實參,那麼在參數前面加上 inout,這個關鍵字不能對可變參數添加,同時加上了這個keyword之後,不能再添加 var let,也不能有默認值。

func add(inout first: Int, _ second: Int) -> Int{
    first = 2;
    return first + second
}

var f = 1;
var s = 2;
let result = add(&f,s)
print(f) //f輸出爲2


函數類型

函數也是一種類型。函數類型由函數定義決定。比如

func add(inout first: Int, _ second: Int) -> Int{
    first = 2;
    return first + second
}
它的函數類型爲 (Int, Int) -> Int

如果沒有參數也沒有返回值的函數,函數類型爲 () -> void,也可以寫爲 () -> (),Void -> Void,Void -> ()

函數類型可以和基本類型一樣,用來定義變量。繼續利用上面定義的add函數

var mathFunc : (inout Int, Int) -> Int = add

var f = 1;
var s = 2;
let result = mathFunc(&f,s)  //使用函數類型

函數類型可以用做參數或返回值,利用上面定義的mathFunc變量,可以有

func add(inout first: Int, _ second: Int) -> Int{
    first = 2;
    return first + second
}

var mathFunc : (inout Int, Int) -> Int = add

func doMath(mathFunc: (inout Int, Int) -> Int, var first: Int, second: Int) {
    print("mathFunc =", mathFunc(&first, second))
    print("first=", first, separator:"")
}

var f = 1;
var s = 2;
doMath(mathFunc, first: f, second: 2)
print("f=", f, separator:"")

大家覺得會輸出什麼呢?答案在下面。請自己思考一下吧。

mathFunc = 4
first=2
f=1


嵌套函數

故名思議,就是在函數裏面再定義函數。這個嵌套函數可以在函數內部調用,也可以作爲返回值返回,使得它可以在其他範圍內進行使用。例子如下

//定義了add 和 sub 兩個嵌套函數,然後用於返回。如果輸入的不是”+“或”-“,那麼返回一個nil。注意giveMeFunc返回的是一個函數類型的可選類型
func giveMeFunc(c: Character) -> ((Int, Int) -> Int)? {
    var method : ((Int, Int) -> Int)?
    switch c {
    case "+" :
        func add(one: Int, _ two: Int) -> Int { return one + two }
        method = add
    case "-" :
        func sub(one: Int, _ two: Int) -> Int { return one - two }
        method = sub
    default :
        method = nil
    }
    return method
}


if let m = giveMeFunc("-") {
    print(m(1,2))  // 打印  -1
}


操作符函數(Operator Functions

swift和C++一樣,可以定義操作符函數。操作符指的是+,-,/,%,+=等等。一般我們這些操作符是給數字類型使用的。但是有了操作符函數之後,我們可以自定義這類符號的運算規則。下面是官方的示例:

struct Vector2D {
    var x = 0.0, y = 0.0
}
func + (left: Vector2D, right: Vector2D) -> Vector2D {
    return Vector2D(x: left.x + right.x, y: left.y + right.y)
}
上面的例子定義了一個操作符函數 + ,這個操作符函數的參數列表裏面有兩個參數left和right。分別代表着+號左右兩邊的兩個參數。通過這個函數,我們可以直接將兩個Vector示例進行相加。如下:

let vector = Vector2D(x: 3.0, y: 1.0)
let anotherVector = Vector2D(x: 2.0, y: 4.0)
let combinedVector = vector + anotherVector
// combinedVector is a Vector2D instance with values of (5.0, 5.0)

除了這種要接受兩個參數的操作符之外,還要一些只有一個參數的操作符,比如 -,++,--等等。但是這類操作符有兩類:前綴(Prefix)和後綴(Postfix),比如--a,i++;

這類操作符的定義要加上prefix或postfix關鍵字。語法如下:

prefix func - (vector: Vector2D) -> Vector2D {
    return Vector2D(x: -vector.x, y: -vector.y)
}
上面定義了一個前綴的 - 操作符函數。用來將一個向量取反。


另外還有一種計算並賦值的操作符,比如++,+=等等。這類的操作符會對其中的一個操作對象進行操作後的賦值。所以必須將參數設置爲inout

func += (inout left: Vector2D, right: Vector2D) {
    left = left + right
}

除了Swift已經定義的操作符之外,還可以自己定義操作符。比如下面定義了一個+++操作符。

prefix operator +++ {}
上面的只是定義,我們還需要實現這個操作符所做的事情。

prefix func +++ (inout vector: Vector2D) -> Vector2D {
    vector += vector
    return vector
}

但是這個自定義的操作符有一些規定。

自定義的操作符可以由/=-+!*%<>&|^?, ~,和某些Unicode 字符開始,至於是哪些字符可以參考官網。點擊網頁,在網頁最下面

在這些字符之後,可以接上unicode字符。

另外有一些禁止的規定:

1.不能重寫一個單單的 ? 號。(可以在字符裏面加入?號)

2.不能重寫這些操作符  =->///**/.,  但是可以重寫兩個或更多個點的操作符。

3. 不能以這些字符開頭 ?,   <, & 

4.不能以這些字符結尾  ?, >, !


在定義的操作符的時候末尾的那對大括號是有用的。在數學上,加減乘除是有優先級和結合規則的。同樣的,這裏的操作符也是。我們可以在定義操作符的大括號裏面定義這個操作符的優先級和結合規律。

infix operator +- { associativity left precedence 140 }
func +- (left: Vector2D, right: Vector2D) -> Vector2D {
    return Vector2D(x: left.x + right.x, y: left.y - right.y)
}
上面例子定義的是一箇中間的操作符,它的結合規則是向左結合。優先級是140.

結合規律有left、right、none三種。不指定的時候默認是none。但是如果是none的話,是不能和同優先級的操作符寫在一起。

優先級不指定的時候默認是100.


參考網頁

Swift函數文檔

Swift高級操作符

Swift詞彙結構

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