0.Swift 统一的函数语法足够灵活,可以用来表示任何函数,包括从最简单的没有参数名字的 C 风格函数,到复杂的带局部和外部参数名的 Objective-C 风格函数。参数可以提供默认值,以简化函数调用。参数也可以既当做传入参数,也当做传出参数,也就是说,一旦函数执行结束,传入的参数值可以被修改。
1.在 Swift 中,每个函数都有一种类型,包括函数的参数值类型和返回值类型。你可以把函数类型当做任何其他普通变量类型一样处理,这样就可以更简单地把函数当做别的函数的参数,也可以从其他函数中返回函数。函数的定义可以写在在其他函数定义中,这样可以在嵌套函数范围内实现功能封装
2.定义一个输入参数-一个叫做 personName
的 String
值,和一个包含给这个人问候语的 String
类型的返回值:
1 2 3 4
| func sayHello(personName: String) -> String { let greeting = "Hello, " + personName + "!" return greeting }
|
3.函数的定义,以 func
作为前缀。指定函数返回类型时,用返回箭头 ->
(一个连字符后跟一个右尖括号)后跟返回类型的名称的方式来表示。
4.函数可以没有参数。下面这个函数就是一个无参函数,当被调用时,它返回固定的 String
消息:
1 2 3 4 5
| func sayHelloWorld() -> String { return "hello, world" } print(sayHelloWorld())
|
5.函数可以有多种输入参数,这些参数被包含在函数的括号之中,以逗号分隔:
1 2 3 4 5 6 7 8 9
| func sayHello(personName: String, alreadyGreeted: Bool) -> String { if alreadyGreeted { return sayHelloAgain(personName) } else { return sayHello(personName) } } print(sayHello("Tim", alreadyGreeted: true))
|
6.当调用超过一个参数的函数时,第一个参数后的参数根据其对应的参数名称标记。
7.函数可以没有返回值。下面是 sayHello(_:)
函数的另一个版本,叫 sayGoodbye(_:)
,这个函数直接输出 String
值,而不是返回它:
1 2 3 4 5
| func sayGoodbye(personName: String) { print("Goodbye, \(personName)!") } sayGoodbye("Dave")
|
8.严格上来说,虽然没有返回值被定义,sayGoodbye(_:)
函数依然返回了值。没有定义返回类型的函数会返回特殊的值,叫 Void
。它其实是一个空的元组(tuple),没有任何元素,可以写成 ()
。
9.你可以用元组(tuple)类型让多个值作为一个复合值从函数中返回。
1 2 3 4 5 6 7 8 9 10 11 12
| 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) }
|
10.如果函数返回的元组类型有可能整个元组都“没有值”,你可以使用可选的(Optional) 元组返回类型反映整个元组可以是 nil
的事实。你可以通过在元组类型的右括号后放置一个问号来定义一个可选元组,例如 (Int, Int)?
或 (String, Int, Bool)?
11.可选元组类型如 (Int, Int)?
与元组包含可选类型如 (Int?, Int?)
是不同的.可选的元组类型,整个元组是可选的,而不只是元组中的每个元素值
1 2 3 4 5 6 7 8 9 10 11 12 13
| 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) }
|
12.函数参数都有一个外部参数名(external parameter name)和一个局部参数名(local parameter name)。外部参数名用于在函数调用时标注传递给函数的参数,局部参数名在函数的实现内部使用。
1 2 3 4 5 6
| func someFunction(firstParameterName: Int, secondParameterName: Int) { } someFunction(1, secondParameterName: 2)
|
13.一般情况下,第一个参数省略其外部参数名,第二个以及随后的参数使用其局部参数名作为外部参数名。所有参数必须有独一无二的局部参数名。尽管多个参数可以有相同的外部参数名,但不同的外部参数名能让你的代码更有可读性。
14.你可以在局部参数名前指定外部参数名,中间以空格分隔:
1 2 3 4
| func sayHello(to person: String, and anotherPerson: String) -> String { return "Hello \(person) and \(anotherPerson)!" } print(sayHello(to: "Bill", and: "Ted"))
|
15.如果你不想为第二个及后续的参数设置外部参数名,用一个下划线(_
)代替一个明确的参数名。
1 2 3 4 5 6
| func someFunction(firstParameterName: Int, _ secondParameterName: Int) { } someFunction(1, 2)
|
16.你可以在函数体中为每个参数定义默认值(Deafult Values)。当默认值被定义后,调用这个函数时可以忽略这个参数。
1 2 3 4 5 6 7
| func someFunction(parameterWithDefault: Int = 12) { } someFunction(6) someFunction()
|
17.将带有默认值的参数放在函数参数列表的最后。这样可以保证在函数调用时,非默认参数的顺序是一致的,同时使得相同的函数在不同情况下调用时显得更为清晰。
18.一个可变参数(variadic parameter)可以接受零个或多个值。函数调用时,你可以用可变参数来指定函数参数可以被传入不确定数量的输入值。通过在变量类型名后面加入(...
)的方式来定义可变参数。
1 2 3 4 5 6 7 8 9 10 11
| func arithmeticMean(numbers: Double...) -> Double { var total: Double = 0 for number in numbers { total += number } return total / Double(numbers.count) } arithmeticMean(1, 2, 3, 4, 5) arithmeticMean(3, 8.25, 18.75)
|
19.一个函数最多只能有一个可变参数。
20.如果函数有一个或多个带默认值的参数,而且还有一个可变参数,那么把可变参数放在参数表的最后。
21.函数参数默认是常量。试图在函数体中更改参数值将会导致编译错误。这意味着你不能错误地更改参数值。
22.通过在参数名前加关键字 var
来定义变量参数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| func alignRight(var string: String, totalLength: Int, pad: Character) -> String { let amountToPad = totalLength - string.characters.count if amountToPad < 1 { return string } let padString = String(pad) for _ in 1...amountToPad { string = padString + string } return string } let originalString = "hello" let paddedString = alignRight(originalString, totalLength: 10, pad: "-")
|
23.对变量参数所进行的修改在函数调用结束后便消失了,并且对于函数体外是不可见的。变量参数仅仅存在于函数调用的生命周期中。
24.变量参数,正如上面所述,仅仅能在函数体内被更改。如果你想要一个函数可以修改参数的值,并且想要在这些修改在函数调用结束后仍然存在,那么就应该把这个参数定义为输入输出参数(In-Out Parameters)。
25.定义一个输入输出参数时,在参数定义前加 inout
关键字。一个输入输出参数有传入函数的值,这个值被函数修改,然后被传出函数,替换原来的值。
26.你只能传递变量给输入输出参数。你不能传入常量或者字面量(literal value),因为这些量是不能被修改的。当传入的参数作为输入输出参数时,需要在参数名前加 &
符,表示这个值可以被函数修改。
27.输入输出参数不能有默认值,而且可变参数不能用 inout
标记。如果你用 inout
标记一个参数,这个参数不能被 var
或者 let
标记。
1 2 3 4 5
| func swapTwoInts(inout a: Int, inout _ b: Int) { let temporaryA = a a = b b = temporaryA }
|
28.你可以用两个 Int
型的变量来调用 swapTwoInts(_:_:)
。需要注意的是,someInt
和 anotherInt
在传入 swapTwoInts(_:_:)
函数前,都加了 &
的前缀:
1 2 3 4 5
| var someInt = 3 var anotherInt = 107 swapTwoInts(&someInt, &anotherInt) print("someInt is now \(someInt), and anotherInt is now \(anotherInt)")
|
29.在 Swift 中,使用函数类型就像使用其他类型一样。例如,你可以定义一个类型为函数的常量或变量,并将适当的函数赋值给它:
1 2 3 4 5
| func addTwoInts(a: Int, _ b: Int) -> Int { return a + b } var mathFunction: (Int, Int) -> Int = addTwoInts
|
30.你可以用 (Int, Int) -> Int
这样的函数类型作为另一个函数的参数类型。这样你可以将函数的一部分实现留给函数的调用者来提供:
1 2 3 4 5
| func printMathResult(mathFunction: (Int, Int) -> Int, _ a: Int, _ b: Int) { print("Result: \(mathFunction(a, b))") } printMathResult(addTwoInts, 3, 5)
|
31.你可以用函数类型作为另一个函数的返回类型。你需要做的是在返回箭头(->
)后写一个完整的函数类型。
1 2 3 4 5 6 7 8 9 10 11
| func stepForward(input: Int) -> Int { return input + 1 } func stepBackward(input: Int) -> Int { return input - 1 } func chooseStepFunction(backwards: Bool) -> (Int) -> Int { return backwards ? stepBackward : stepForward }
|
32.这章中你所见到的所有函数都叫全局函数(global functions),它们定义在全局域中。你也可以把函数定义在别的函数体中,称作嵌套函数(nested functions)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| func chooseStepFunction(backwards: Bool) -> (Int) -> Int { func stepForward(input: Int) -> Int { return input + 1 } func stepBackward(input: Int) -> Int { return input - 1 } return backwards ? stepBackward : stepForward } var currentValue = -4 let moveNearerToZero = chooseStepFunction(currentValue > 0) while currentValue != 0 { print("\(currentValue)... ") currentValue = moveNearerToZero(currentValue) } print("zero!")
|