type
status
date
slug
summary
tags
category
icon
password
example-row
example-row

函数概念

  • 函数是一个独立的代码块,用来执行特定的任务。通过给函数一个名字来定义它的功能,并且在需要的时候,通过这个名字来“调用”函数执行它的任务。
  • Swift统一的函数语法十分灵活,可以表达从简单的无形式参数的C风格函数到复杂的每一个形式参 数都带有局部和外部形式参数名的Objective-C风格方法的任何内容。形式参数能提供一个默认的值 来简化函数的调用,也可以被当作输入输出形式参数被传递,它在函数执行完成时修改传递来的变量。
  • Swift中的每一个函数都有类型,由函数的形式参数类型和返回类型组成。你可以像Swift中其他类 型那样来使用它,这使得你能够方便的将一个函数当作一个形式参数传递到另外的一个函数中,也可 以在一个函数中返回另一个函数。函数同时也可以写在其他函数内部来在内嵌范围封装有用的功能。
  • 当你定义了一个函数的时候,你可以选择定义一个或者多个命名的分类的值作为函数的输入(所谓的形式参数),并且/或者定义函数完成后将要传回作为输出的值的类型(所谓它的返回类型)。
  • 每一个函数都有一个函数名,它描述函数执行的任务。要使用一个函数,你可以通过“调用” 函数的名字并且传入一个符合函数形式参数类型的输入值(所谓实际参数)来调用这个函数。 给函数提供的实际参数的顺序必须符合函数的形式参数列表顺序。

一般用法

  • 所有的函数前面都用func来修饰。
  • 函数名()()里写的是参数,这里是虚参,也就是参数名称。
  • 函数的参数默认是常量,你可以通过使用inout关键字来使它们变成可变的,本质是将值传递改为了指针传递。
    • 可变参数不可以加inout
    • inout参数不可以有默认值。
  • 返回值是写在参数的后面,并且使用->隔开,sum函数返回的是Int类型。
  • 在调用时也需要加上参数名称,这样传值会更准确。
  • 因为是单一的表达式,所以无需写return,编译期会自动判断。
  • 若没有返回值有三种写法
    • 返回VoidVoid其实就是()Void()空元祖的别名(注意Void的V是大写,跟其他语言不一样)。
    • 返回(),也就是直接返回空元组。
    • 也可以不写返回值就表示没有返回值。
  • 如果整个函数体只是简单的单一表达式,可以不写return来返回,编译器会自动帮我们增加return

返回元组

  • 以元组的形式返回就可以一次性得到多个返回值。
  • 函数接收的时候就直接用一个let或var就行,因为他们是不确定数据类型的,所以可以接收任意类型。
  • 接收后使用上就和正常的元组一样了,可以通过标识符取用,也可以使用下标取用。

函数参数

无形式参数

  • 函数没有要求必须输入一个参数,可以没有形式参数。
  • 函数的定义仍然需要在名字后边加一个圆括号,即使它不接受形式参数也得这样做。当函数被调用的时候也要在函数的名字后边加一个空的圆括号。

参数标签

  • 在函数定义中使用的是time作为参数名称,这样更易读,this time is 10:00
  • 在函数调用时用go to work at 10:00这样来写更易读,所以在定义函数时加上at作为参数标签。
  • 函数的一个参数既有在函数内部使用的参数名称,也有在函数外使用的函数标签。
  • 函数标签可以省略,使用_就可以省略,此时外部调用时就无需使用参数标签。
  • 这种加_省略和不写参数标签是不一样的。如示例所见,使用_省略参数标签的写法,函数在调用时可以直接传值,如果是定义时不写参数标签,在外部调用时仍然要写参数名称,而不能直接写参数。

默认参数

在定义函数时添加默认参数,在调用函数时可以不传入这个参数的值。
  • 上面函数中namejob参数有配置默认参数值。
  • 在调用时函数时如果不给namejob传值,函数内部会使用默认参数值计算。而age没有配置默认参数值,所以必须要传值。
  • 因为在传值时会使用到参数标签,所以像check(age: 18,job: "iOS")这种少一个函数参数赋值的写法是不会有歧义的。
  • 虽然使用了函数标签,但是像check(age: 18,name:"bbb")这种和定义的函数顺序不一致的写法是不被允许的。

可变参数

在Swift中可变参数和其他语言一样,其内部也是编译成一个数组。
  • 可变参数的写法:传入的参数中在数据类型的后面加上...
  • 在函数内部把这个参数看做数组来处理。
  • 一个函数能拥有多个可变参数。
  • 紧跟在可变参数后面的参数不能省略参数标签/参数名称,否则无法区分实参是传递给可变参数,还是后面的形参。

输入输出参数

函数参数默认是常量。试图在函数体中更改参数值将会导致编译错误。如果想要一个函数可以修改参数的值,并且想要在这些修改在函数调用结束后仍然存在,那么就应该把这个参数定义为输入输出参数(In-Out Parameters)。
  • 参数定义前加 inout 关键字。
  • 输入输出参数不能有默认值,而且可变参数不能用 inout 标记。
  • 只能传递变量给输入输出参数。
  • 当传入的参数作为输入输出参数时,需要在参数名前加 & 符,表示这个值可以被函数修改。

函数数据类型

函数的数据类型就是参数数据类型 + 返回值数据类型

函数作为变量

  • 定义一个函数类型的变量,将一个函数赋值给这个变量,之后通过这个变量来调用函数。
  • 通过函数变量调用时不需要参数标签和参数名称,直接传值。
  • 这里为了更方便的说明,所以把定义变量和赋值参数分开写了,其实可以把12写成一行:var fn2: (Int,Int) -> Int = sum(a:b:)

函数作为参数传递

  • printResult函数中第一个参数是一个函数,这里传递的参数的数据类型是函数类型。
  • (Int, Int) -> IntmathFn参数的数据类型。
  • PrintResult函数中使用传入的函数进行调用,通过传入的函数和对变量进行对应的加减操作。

嵌套函数

全局函数(global functions)是定义在全局域中,而嵌套函数(nested functions)定义在函数体内。默认情况下,嵌套函数是对外界不可见的,但是可以被它们的外围函数(enclosing function)调用。一个外围函数也可以返回它的某一个嵌套函数,使得这个函数可以在其他域中被使用。
可以用返回嵌套函数的方式重写 上面的chooseStepFunction(backward:) 函数:

其他

函数重载

函数重载的方法名必须相同,参数必须不同,参数不同包括:
  • 参数个数不同
  • 参数类型不同
  • 参数标签不同
注意:
  • 与java不同的是,返回值类型是否相同与函数重载无关。
  • 默认参数值和函数重载一起使用会产生二义性,但是不会编译报错,需要注意。

内联函数

内联函数会将函数调用展开成函数体,我们可以手动设置是否是内联函数,但没必要,编译器开启编译优化后会自动生成。
  • 当开启编译期优化后,系统会自动把一些函数变为内联函数。
  • 内联函数就是将函数调用展开成函数体。
  • 这样可以减少函数的调用,减少函数栈的开辟,提高了代码执行效率,也节约了栈空间。
函数不会被自动内联的情况:
  • 函数体比较长。
  • 包含递归调用。
  • 包含动态绑定,即在多态中动态的给变量绑定类型。
手动配置内联函数:

设置别名typealias

typealias可以给任意的类型起别名
所以Void是空元组的别名,等价于就是空元组。

参考:

【swift010】注释【swift012】闭包
  • Twikoo