swift之函数(functions)

函数是用来完成特定任务的独立代码块

Swift 统⼀的函数语法⾜够灵活,可以⽤来表⽰任何函数,包括从最简单的没有参数名字的 C ⻛格函数,到复杂的带局部和外部参数名的 Objective-C ⻛格函数。参数可以提供默
认值,以简化函数调⽤。参数也可以既当做传⼊参数,也当做传出参数,也就是说,⼀旦函数执⾏结束,传⼊的参数值可以被修改。

在 Swift 中,每个函数都有⼀种类型,包括函数的参数值类型和返回值类型。你可以把函数类型当做任何其他普通变量类型⼀样处理,这样就可以更简单地把函数当做别的函数的
参数,也可以从其他函数中返回函数。函数的定义可以写在在其他函数定义中,这样可以在嵌套函数范围内实现功能封装。

1、函数的定义与调用

定义一个函数时,可以定义⼀个或多个有名字和类型的值,作为函数的输⼊(称为参数,parameters),也可以定义某种类型的值作为函数执⾏结束的输出(称为返回类型)。

每个函数有个函数名,⽤来描述函数执⾏的任务。要使⽤⼀个函数时,你⽤函数名“调⽤”,并传给它匹配的输⼊值(称作实参,arguments)。⼀个函数的实参必须与函数参数表⾥参数的顺序⼀致。

//myAge myName就是参数标签,可有可无,写出来可以清楚的知道参数的意思,跟oc中一样
//参数1  age 类型Int,参数2  name 类型String,返回值类型  String
func callFunc(myAge age : Int, myName name : String) -> String {
    return  "name:" + name + ",age:" + String(age)
}
print(callFunc(myAge: 25, myName: "dzl"))//这里直接输出函数返回值

//name:dzl,age:25
//Program ended with exit code: 0

2、函数参数与返回值
函数参数与返回值在Swift中极为灵活。你可以定义任何类型的函数,包括从不带参数的简单函数到复杂的带有表达性参数名和不同参数选项的复杂函数。

(1)无参函数

//下面这两种形式都是无参,无返回值的函数,当没有返回值时,可以指定返回值类型为Void,也可以省略不写
func noParameter() -> Void {
    print("no parametr, no return value")
}
func noParameter2() {
    print("no parametr2, no return value")
}
noParameter()
noParameter2()

//no parametr, no return value
//no parametr2, no return value

(2)多重输入参数,多参量函数(就是参数类型不一样)

函数可以有多个参数,写在圆括号中,用逗号分隔

//三个输入参数
func multipleParameter(age : Int, name : String, sex : String) {
    print("Person name is (name), age is (age), sex is (sex)")
}
multipleParameter(22, name: "Tom", sex: "boy")

//Person name is Tom, age is 22, sex is boy

(3)多重返回值函数
可以⽤元组(tuple)类型让多个值作为⼀个复合值从函数中返回。

func returnTuple(name : String, englishScore : Double, mathScore : Double, chineseScore : Double) -> (describe : String, averageScore : Double) {
    return ("name is " + name + ",englishScore is " + String(englishScore) + ",mathScore is " + String(mathScore) + ",chineseScore is " + String(chineseScore), (mathScore + englishScore + chineseScore) / 3)
}
var receive = returnTuple("dzl", englishScore: 70, mathScore: 80, chineseScore: 90)
print("(receive.describe), average is (receive.1)")  //两种访问元组元素的方式

//name is dzl,englishScore is 70.0,mathScore is 80.0,chineseScore is 90.0, average is 80.0

3、函数参数名称

函数参数都有⼀个外部参数名(external parameter name)和⼀个本地参数名(local parameter name).外部参数名⽤来标记传递给函数调⽤的参数,本地参数名在实现函数的时
候使⽤

如(3)中例子

⼀般情况下,第⼀个参数省略其外部参数名,第⼆个以后的参数使⽤其本地参数名作为⾃⼰的外部参数名.所有参数需要有不同的本地参数名,但可以共享相同的外部参数名

(1)指定外部参数名:

如1中例子

(2)忽略外部参数名:

如果你不想为第⼆个及后续的参数设置参数名,⽤⼀个下划线(_)代替⼀个明确地参数名

func ignoreParatemer(name : String, _ age : Int){
    print("test ignore parameter, name is  (name), age is (age)")
}
ignoreParatemer("dzl", 22)

//test ignore parameter, name is  dzl, age is 22

(3)默认参数值
可以在函数体中为每个参数定义 默认值(Deafult Values)  。当默认值被定义后,调⽤这个函数时可以忽略这个参数

注意: 将带有默认值的参数放在函数参数列表的最后。这样可以保证在函数调⽤时,⾮默认参数的顺序是⼀致的,同时使得相同的函数在不同情况下调⽤时显得更为清晰

func defaultValue(name : String, englishScore : Double, mathScore : Double = 80.00, chineseScore : Double = 90.00) {
    print("name is (name), englishScore is (englishScore), mathScore is (mathScore), chineseScore is (chineseScore)")
}
//三种调用方式
defaultValue("dzl", englishScore: 60)
defaultValue("dzl", englishScore: 65, mathScore: 81)
defaultValue("dzl", englishScore: 70, mathScore: 85, chineseScore: 95)

//三种输出
name is dzl, englishScore is 60.0, mathScore is 80.0, chineseScore is 90.0
name is dzl, englishScore is 65.0, mathScore is 81.0, chineseScore is 90.0
name is dzl, englishScore is 70.0, mathScore is 85.0, chineseScore is 95.0

(4)可变参数
⼀个 可变参数(variadic parameter)  可以接受零个或多个值。函数调⽤时,你可以⽤可变参数来传⼊不确定数量的输⼊参数。通过在变量类型名后⾯加⼊ (...)  的⽅式来定义可变参数。

func changeableParameter(scores : Double ...){
    var totalScore : Double = 0
    for score in scores {
        totalScore += score
    }
    print("the average score is (totalScore/Double(scores.count))")
}
changeableParameter(12.0, 34.0, 90.0, 32)
changeableParameter(65, 70)

//the average score is 42.0
//the average score is 67.5

(5)常量参数和变量参数
函数参数默认是常量。试图在函数体中更改参数值将会导致编译错误。这意味着你不能错误地更改参数值。
但是,有时候,如果函数中有传⼊参数的变量值副本将是很有⽤的。你可以通过指定⼀个或多个参数为变量参数,从⽽避免⾃⼰在函数中定义新的变量。变量参数不是常量,你可以在函数中把它当做新的可修改副本来使⽤。
通过在参数名前加关键字  var  来定义变量参数:

func varParameter(var name : String, score : Double) {
    name += (":" + String(score))  //可以修改name的值
    print(name)
}
varParameter("dzl", score: 90)
//dzl:90.0

(6)输入输出参数
变量参数,正如上⾯所述,仅仅能在函数体内被更改。如果你想要⼀个函数可以修改参数的值,并且想要在这些修改在函数调⽤结束后仍然存在,那么就应该把这个参数定义为输⼊输出参数(In-Out Parameters)。
定义⼀个输⼊输出参数时,在参数定义前加  inout  关键字。⼀个输⼊输出参数有传⼊函数的值,这个值被函数修改,然后被传出函数,替换原来的值。
你只能将变量作为输⼊输出参数。你不能传⼊常量或者字⾯量(literal value),因为这些量是不能被修改的。当传⼊的参数作为输⼊输出参数时,需要在参数前加 &  符,表⽰这个值可以被函数修改。
注意: 输⼊输出参数不能有默认值,⽽且可变参数不能⽤  inout  标记。如果你⽤inout  标记⼀个参数,这个参数不能被  var  或者  let  标记。

func inoutParameter(inout a : Int, inout b : Int) {
    let temp = a
    a = b
    b = temp
}
var a = 10
var b = 20
print("a is (a), b is (b)")
inoutParameter(&a, b: &b)
print("a is (a), b is (b)")

//a is 10, b is 20
//a is 20, b is 10

4、函数类型
每个函数都有种特定的函数类型,由函数的参数类型和返回类型组成

例如:

func addTwoInts(a: Int, _ b: Int) -> Int {
    return a + b
}
func multiplyTwoInts(a: Int, _ b: Int) -> Int {
    return a * b
}

这个例⼦中定义了两个简单的数学函数: addTwoInts  和  multiplyTwoInts  。这两个函数都传⼊两个  Int  类型, 返回⼀个合适的 Int  值。
这两个函数的类型是  (Int, Int) -> Int  ,可以读作“这个函数类型,它有两个  Int  型的参数并返回⼀个  Int  型的值。
下⾯是另⼀个例⼦,⼀个没有参数,也没有返回值的函数:

func printHelloWorld() {
    print("hello, world")
}

这个函数的类型是: () -> void  ,或者叫“没有参数,并返回  Void  类型的函数”。

(1)使用函数类型

func useFuncType(a : Int, _ b : Int) -> Int {
    return a + b
}
//定义⼀个叫做 varFuncType 的变量,类型是‘⼀个有两个 Int 型的参数并返回⼀个 Int 型的值的函数’,并让这个新变量指向 useFuncType 函数
var varFuncType : (Int, Int) -> Int = useFuncType
//然后我们就可以用varFuncType来调用useFuncType函数了
print(varFuncType(10, 20))

//还可以让它自己推断变量类型
var varFuncType2 = useFuncType
print(varFuncType2(100, 200))

//30
//300

(2)函数类型作为参数类型

func func1(a : Int, b : Int) -> Int {
    return a + b
}
func func2(a : Int, b : Int) -> Int {
    return a * b
}
func func3(funcParameter : (Int, Int) -> Int, a : Int, b : Int) {
    let result = funcParameter(a, b)
    print(result)
}
func3(func1, a: 10, b: 20)
func3(func2, a: 10, b: 20)

//30
//200

(3)函数类型作为返回值

func returnValue1(a : Int, b : Int) -> Int {
    return a + b
}
func returnValue2(a : Int, b : Int) -> Int {
    return a * b
}
func returnValue3(retFunc : Bool) -> (Int, Int) -> Int {
    if retFunc {
        return returnValue1
    }else {
        return returnValue2
    }
}
print(returnValue3(true)(10, 20))
print(returnValue3(false)(10, 20))

//30
//200

5、嵌套函数
前面你所⻅到的所有函数都叫全局函数(global functions),它们定义在全局域中。你也可以把函数定义在别的函数体中,称作嵌套函数(nested functions)

默认情况下,嵌套函数是对外界不可⻅的,但是可以被他们封闭函数(enclosing function)来调⽤。⼀个封闭函数也可以返回它的某⼀个嵌套函数,使得这个函数可以在其他域中被使⽤。

func returnValue13(retFunc : Bool) -> (Int, Int) -> Int {
    //这两个函数对外是不可见的,但是可以通过returnValue13 访问
    func returnValue11(a : Int, b : Int) -> Int {
        return a + b
    }
    func returnValue12(a : Int, b : Int) -> Int {
        return a * b
    }
    
    if retFunc {
        return returnValue11
    }else {
        return returnValue12
    }
}

print(returnValue13(true)(10, 20))
print(returnValue13(false)(10, 20))

//30
//200

文章导航