Swift 学习- 07 -- 函数

Posted Dingzhijie

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Swift 学习- 07 -- 函数相关的知识,希望对你有一定的参考价值。

// 函数

// 函数是一段完成特定任务的独立代码片段, 你可以通过给函数命名来标识某个函数的功能, 这个名字可以被用来在需要的时候‘调用‘这个函数来完成它的任务 

// swift 统一的函数语法非常的灵活, 可以用来表示任何函数, 包括从简单的没有参数名字的 C 风格函数, 到复杂的带局部的外部参数 OC 风格函数, 参数可以提供默认值, 以简化函数调用, 参数也可以即当做传入参数, 也当做传出参数,也就是说, 一旦函数执行结束, 传入的参数值会被修改

 

// 在 swift 中, 每个参数都有一个由函数的参数值类型和返回值类型组成的类型, 你可以把函数类型当做任何其它普通变量类型一样处理,这样就可以更简单地把函数当做别的函数的参数,也可以从其它函数中返回函数, 函数的定义可以写在其它函数的定义中,这样可以在嵌套函数范围内实现功能封装.

 

// 函数的定义与调用

// 当你定义一个函数时, 你可以定义一个或多个有名字和类型的值, 作为函数的输入, 称为参数, 也可以定义某种类型的值作为函数执行结束时的输出, 称为返回类型

 

// 每个函数有个函数名, 用来描述函数执行的任务, 要使用一个函数时, 用函数名来调用这个函数, 并传给它匹配的输入值(称作 实参), 函数的实参必须与函数参数里参数的顺序一致

 

func greet(person: String) -> String{

    let greeting = "hello," + person + "!"

    return greeting

}

 

// 函数的定义, 以 func 作为前缀, 指定函数返回类型时, 用返回箭头 -> (一个连字符后面跟一个右尖括号) 后跟返回类型的名称方式来表示

// 该定义描述了函数的功能, 它期望接收什么作为参数和执行结束时它返回的结果是什么类型

 

print(greet(person: "ahhh"))

 

// 注意 : prient(_:separator:terminator:) 函数的第一个参数并没有设置一个标签, 而其它的参数因为有了默认值, 因此是可选的

 

 

func greenAgain(person: String) -> String{

    return "hello," + person + "!"

}

 

print(greenAgain(person: "houdehcneg"))

 

 

// 函数的类型与返回值

// 函数参数与返回值在 swift 中非常的灵活, 你可以定义任何类型的函数, 包括从只带一个未命名参数的简单函数到复杂的带有表达式参数名和不同参数选项的复杂函数

 

 

// 无参数函数

// 函数可以没有参数,

func sayHelloWorld() -> String{

    return "Hello,World!"

}

 

print(sayHelloWorld())

 

// 尽管这个函数没有参数,但是定义中在函数名后还是需要一堆圆括号, 当被调用时,也需要在函数名写一对圆括号

 

 

// 多参数函数

// 函数可以有多种输入参数, 这些参数被包含在函数的括号内, 以逗号分隔

func greet(person: String,alreadyGreeted: Bool) -> String{

    if alreadyGreeted {

        return greenAgain(person: person)

    }else{

        return greet(person: person)

    }

}

 

print(greet(person: "timw", alreadyGreeted: true))

 

 

 

// 无返回值函数

// 函数可以没有返回值, 下面是 greet(person:)函数的另一个版本,这个函数 直接打印一个 String值, 而不是返回它:

 

func greet2(person: String){

    print(person)

}

 

// 因为这个函数不需要返回值, 所以函数的定义中没有返回箭头 (->) 和返回类型

// 注意 : 严格上来说, 虽然没有返回值被定义, greet(person:) 函数依然返回了值,没有定义返回值的函数会返回一个特殊的 Void 值, 它其实是一个空的元组, 没有任何元素, 可以写成 ()

 

// 注意 : 返回值可以被忽略, 但是定义了有返回值的函数必须返回一个值, 如果在函数定义底部没有返回任何值, 将导致编辑错误

 

 

// 多重返回值函数

// 你可以用元组 (tuple) 类型让多个值作为一个复合值从函数中返回

 

func minMax(array: [Int]) ->(min: Int, max: Int){

    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)

}

 

let bounds = minMax(array: [8,-5,2,109,-21,71])

print("min is \(bounds.min) ,max is \(bounds.max)")

 

// 需要注意的是, 元组的成员不需要在元组从函数中返回,因为它们的名字已经在函数的返回类型中指定了

 

 

// 可选元组返回类型

// 如果函数返回的元组类型有可能整个元组都 ‘没有值‘, 你可以使用可选的 (optional) 元组返回类型反映整个元组可以为 nil 的事实, 你可以通过在元组类型的右括号后放置一个问号来定义一个可选元组,例如 (Int,Int)?

// 注意 : 可选元组类型如 (Int,Int)? 与元组包含可选类型如 (Int?,Int?)是不同的, 可选的元组类型,整个元组是可选的, 而不是元组中的某个元素值

 

// 前面的例子 minMax(array:) 函数返回了一个包含两个 Int 值的元组,但是函数不会对传入的数组执行任何检查,如果传入的 Array 参数是一个空数组,会触发运行时错误,为了安全地处理这个空数组问题, 将 minMax(array:) 函数改写成可选元组的返回类型, 并且当数组为空时返回 nil

 

func minMax2(array: [Int]) -> (min: Int,max:Int)?{

    if array.isEmpty {

        return nil

    }else{

        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)

    }

        

}

 

// 你可以用可选绑定来检查 minMax2(array:) 函数返回的是一个存在的元组还是 nil

 

if let bounds2 = minMax2(array: [8, -6, 2, 109, 3, 71]) {

    print("min is \(bounds.min) and max is \(bounds.max)")

}

 

 

 

// 函数参数标签和参数名称

// 每个函数参数都有一个参数标签 以及 一个参数名称, 参数标签在调用函数的时候使用,调用的时候需要将函数的参数标签写在对应的参数前面, 参数名称在函数的实现中使用 , 默认情况下,函数参数使用参数名称作为衙门的参数标签

 

// 所有的参数都必须有独一无二的名字,

 

 

// 指定参数标签

// 你可以在函数名称前指定它的参数标签, 中间已空格分割

 

func someFunction(argumentlabel arameterName: Int){

    print(arameterName)

}

 

someFunction(argumentlabel: 5)

 

 

// 忽略参数标签

// 如果你不希望某个参数添加一个标签, 可以使用一个下划线(_)来代替一个明确的参数标签

 

func someFunction2(_ firstParameterName:Int, seconedParamerer:Int){

    print(firstParameterName + seconedParamerer)

}

 

someFunction2(8, seconedParamerer: 8)

 

// 如果一个参数有一个标签, 那么在调用的时候必须使用标签来标记这个参数

 

 

// 默认参数值

// 你可以在函数体中通过给参数赋值来任意一个函数的参数定义默认值 (Deafult Value), 当默认值被定义后,调用这个函数是可以忽略这个参数

 

func someFunction3(parameterWithoutDefault:Int,parameterWithDefault:Int = 12){

    print(parameterWithDefault + parameterWithoutDefault)

}

 

someFunction3(parameterWithoutDefault: 8, parameterWithDefault: 8)

 

someFunction3(parameterWithoutDefault: 8)

 

// 将不带有默认值的参数放在函数参数列表的最前面, 一般来说, 没有默认值的参数更加的重要, 将不带有默认值的参数放在最前面保证在函数调时,非默认参数的顺序是一致的,同事也使得相同的函数在不同的情况下调用时显得更为清晰

 

 

// 可变参数

// 一个可变参数 可以接受 0 个 或者多个值, 函数调用时,你可以用可变参数来指定函数参数可以被传入的不确定数量的输入值, 通过在变量类型后面加(...)的方式来定义可变参数

 

// 可变参数的传入值在函数体中变为次类型的一个数组,

 

func arithmeticMean(_ numbers:Double...) -> Double{

    var total: Double = 0

    for number in numbers {

        total += number

    }

    return total / Double(numbers.count)

}

 

print(arithmeticMean(45.4,78.5,96.2,151,151,2551,96.58))

 

// 注意 : 一个函数最多可以拥有一个可变参数

 

 

 

// 输入输出参数

// 函数参数默认是常量, 试图在函数体中更改参数值将会导致编辑错误.这意味着你不能错误地更改参数值,如果你想要一个函数可以修改参数的值, 并且想要在这些修改函数调用结束后仍然存在,那么就应该把这个参数定义为输入输出函数

 

// 定义一个输入输出函数时,在参数定义前加 inout 关键字, 一个 输入输出参数 有传入函数的值,这个值被函数修改,然后被传出函数,替换原来的值,

 

// 你只能传递变量给输入输出参数,你不能传入常量或者字面量,因为这些量是不能被修改的,当传入的参数作为输入输出参数时,需要在参数名前加 & 符, 表示这个值可以被函数修改

 

// 注意 : 输入输出参数不能有默认值, 而且可变参数不能用 inout 标记

 

func swapTwoInts(_ a: inout Int,_ b: inout Int){

    let temporaryA = a

    a = b

    b = temporaryA

}

 

// 调用

var someInt = 3

var antherInt = 107

swapTwoInts(&someInt, &antherInt)

print("a is :\(someInt), b is :\(antherInt)")

 

 

// 从上面的例子中,我们可以看到 someInt 和 antherInt 的原始值在 swapTwoInts(_:_:) 函数中被修改,尽管它们的定义在函数体外

 

// 注意 : 输入输出参数和返回值不一样的,上面的swapTwoInts 函数并没有定义任何返回值,但仍然修改了 someInt 和 anotherInt 的值, 输入输出参数是函数对函数体外产生影响的另一种方式

 

 

// 函数类型

// 每个函数都有特定的函数类型, 函数的类型有函数的参数类型和返回值类型组成

 

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 类型的值‘

 

 

// 使用函数类型

// 在 swift 中,使用函数类型就像使用其他类型一样, 例如, 你可以定义一个类型为函数的常量或变量, 并将适当的函数赋值给它

 

var mathFunction: (Int,Int) ->Int = addTwoInts(_:_:)

 

// 这段代码可以理解为. 定义一个叫做mathFunction 的变量,类型是‘一个有两个 Int 类型的参数 并返回每一个 Int 类型的值的函数‘, 并让这个新变量指向 addTwoInts 函数

// mathFunction 和 addTwoInts 有同样的类型, 所以这个赋值过程在 Swift 类型检查(type-check)中是允许的

 

// 现在你可以用 mathFunction 来调用赋值的函数

 

print("Result: \(mathFunction(2,5))")

 

// 有相同匹配类型的不同函数可以被赋值给同一个变量, 就像非函数类型的变量一样

mathFunction = multiplyTwoInts(_:_:)

 

print("Result: \(mathFunction(5,8))")

 

// 就像其他类型一样,当赋值一个函数给常量或者变量时,你可以让 swift 来推断其函数类型

 

let antherMathFunction = addTwoInts

// antherMathFunction 被推断为 (Int,Int) ->Int 类型

 

 

// 函数类型作为参数类型

// 你可以用 (Int, Int) -> Int 这样的函数类型作为另一个函数的参数类型, 这样你可以将函数的一部分实现留给函数的调用者来提供

func printMathResult(_ mathFunction: (Int, Int) -> Int, _ a: Int, _ b: Int){

    print("Result: \(mathFunction(a,b))")

}

 

printMathResult(addTwoInts(_:_:), 8, 5)

 

// 这个例子定义了printMathResult(_:_:_:)函数, 它有三个参数, 第一个参数叫 mathFunction, 类型是 (Int, Int) -> Int, 你可以传入任何这种类型的函数, 第二个和第三个参数叫做 a 和 b ,他们的类型是 Int, 这两个值作为已给出的函数的输入值

// 当 printMathResult(_:_:_:) 被调用时,它被传入 addTwoInts 函数和整数 a 和 b ,它用传入的 a 和 b 来调用 addTwoInts(_:_:), 并输出结果

// printMathResult(_:_:_:) 函数的作用就是输出另一个适当类型的数学函数的调用结果, 它不关心传入函数是如何实现的.只关心传入的函数是不是一个正确的类型,这使得 printMathResult(_:_:_:) 能以一种类型安全 (type-safe)的方式将一部分功能转给调用者实现

 

 

 

// 函数类型作为返回类型

// 你可以用函数类型作为另一个函数的返货类型, 你需要做的是返回箭头 (->) 后写一个完整的函数类型

// 下面的这个例子中定义了两个简单的函数, 这两个函数的类型都是 (Int) -> Int

 

func stepForward(_ input: Int) -> Int{

    return input + 1

}

 

func stepBackward(_ input: Int) -> Int{

    return input - 1

}

 

// 下面的函数的返回类型是 (Int) -> Int 类型的函数,

 

func chooseStepFunction(backward: Bool) -> (Int) -> Int{

    return backward ? stepBackward(_:) : stepForward(_:)

}

 

// 你可以用 chooseStepFunction(backward:) 来获取两个函数其中的一个

 

var currentValue = 3

let moveNearerToZero = chooseStepFunction(backward: currentValue > 0)

 

print(moveNearerToZero(currentValue))

 

 

 

// 嵌套函数

// 到目前为止本章中你所见到的所有函数都叫做全局函数 (global functions), 它们定义在全局域中,你也可以把函数定义在别的函数体中, 称作 嵌套函数(nested functions)

 

// 默认情况下,嵌套函数是对外界不可见的, 但是可以被它们的外围函数 (enclosing function) 调用, 一个外围函数也可以返回它的某一个嵌套函数, 使得这个函数可以在其他域中被使用

 

// 你可以用返回嵌套函数的方式重写 chooseStepFunction(backward:)函数

 

func chooseStepFunction2(backward: Bool) -> (Int) -> Int {

    func stepForward(input: Int) -> Int { return input + 1 }

    func stepBackward(input: Int) -> Int { return input - 1 }

    return backward ? stepBackward : stepForward

}

var currentValue2 = -4

let moveNearerToZero2 = chooseStepFunction(backward: currentValue > 0)

print(moveNearerToZero2(currentValue2))

 

以上是关于Swift 学习- 07 -- 函数的主要内容,如果未能解决你的问题,请参考以下文章

Swift 4 编程语言,输入参数不适用于函数类型作为参数

在 Swift 的 UIKit 文档中查找有关构造函数的信息

Swift学习Array学习深入浅出Swift高阶函数-MapFlatMapCompactMapCompactMapValuesFilterReduce

swift学习笔记2——函数闭包

Swift 学习笔记 (函数)

新 Swift 类的 void 函数中出现意外的非 void 返回值