函数的定义与调用(Defining and Calling Functions)
- 以func作为前缀
- 指定函数返回类型时,用返回箭头 ->(一个连字符后跟一个右尖括号)后跟返回类型的名称的方式来表示
func sayHello(personName: String) -> String {
let greeting = "Hello, " + personName + "!"
return greeting
}
print(sayHello("Anna"))
// prints "Hello, Anna!"
print(sayHello("Brian"))
// prints "Hello, Brian!"
函数参数与返回值(Function Parameters and Return Values)
- 函数如果不需要返回值,函数的定义中可以没有返回箭头(->)和返回类型
func sayGoodbye(personName: String) {
print("Goodbye, \(personName)!")
}
sayGoodbye("Dave")
// prints "Goodbye, Dave!"
- 可以用元组(tuple)类型让多个值作为一个复合值从函数中返回
- 如果函数返回的元组类型有可能整个元组都“没有值”,你可以使用可选的(Optional) 元组返回类型反映整个元组可以是nil的事实。你可以通过在元组类型的右括号后放置一个问号来定义一个可选元组,例如(Int, Int)?或(String, Int, Bool)?
- 可选元组类型如(Int, Int)?与元组包含可选类型如(Int?, Int?)是不同的.可选的元组类型,整个元组是可选的,而不只是元组中的每个元素值。
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)
}
if let bounds = minMax([8, -6, 2, 109, 3, 71]) {
print("min is \(bounds.min) and max is \(bounds.max)")
}
// prints "min is -6 and max is 109"
函数参数名称(Function Parameter Names)
- 函数参数都有一个外部参数名(external parameter name)和一个局部参数名(local parameter name)。外部参数名用于在函数调用时标注传递给函数的参数,局部参数名在函数的实现内部使用。
- 可以在局部参数名前指定外部参数名,中间以空格分隔;如果提供了外部参数名,那么函数在被调用时,必须使用外部参数名。
- 使用外部函数名可以使函数以一种更富有表达性的类似句子的方式调用,并使函数体意图清晰,更具可读性。
- 一般情况下,第一个参数省略其外部参数名,第二个以及随后的参数使用其局部参数名作为外部参数名。
- 如果不想为第二个及后续的参数设置外部参数名,用一个下划线(_)代替一个明确的参数名。因为第一个参数默认忽略其外部参数名称,显式地写下划线是多余的。
func sayHello(to person: String, and anotherPerson: String) -> String {
return "Hello \(person) and \(anotherPerson)!"
}
print(sayHello(to: "Bill", and: "Ted"))
// prints "Hello Bill and Ted!"
func sayHello(person: String, anotherPerson: String) -> String {
return "Hello \(person) and \(anotherPerson)!"
}
print(sayHello( "Bill", anotherPerson: "Ted"))
// prints "Hello Bill and Ted!"
func sayHello(person: String, _ anotherPerson: String) -> String {
return "Hello \(person) and \(anotherPerson)!"
}
print(sayHello("Bill", "Ted"))
// prints "Hello Bill and Ted!"
- 你可以在函数体中为每个参数定义默认值(Deafult Values)。当默认值被定义后,调用这个函数时可以忽略这个参数。
- 将带有默认值的参数放在函数参数列表的最后。这样可以保证在函数调用时,非默认参数的顺序是一致的,同时使得相同的函数在不同情况下调用时显得更为清晰。
func someFunction(parameterWithDefault: Int = 12) {
// function body goes here
// if no arguments are passed to the function call,
// value of parameterWithDefault is 12
}
someFunction(6) // parameterWithDefault is 6
someFunction() // parameterWithDefault is 12
- 一个可变参数(variadic parameter)可以接受零个或多个值。函数调用时,你可以用可变参数来指定函数参数可以被传入不确定数量的输入值。通过在变量类型名后面加入(...)的方式来定义可变参数。
- 可变参数的传入值在函数体中变为此类型的一个数组。
- 一个函数最多只能有一个可变参数。
- 如果函数有一个或多个带默认值的参数,而且还有一个可变参数,那么把可变参数放在参数表的最后。
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)
// returns 3.0, which is the arithmetic mean of these five numbers
arithmeticMean(3, 8.25, 18.75)
// returns 10.0, which is the arithmetic mean of these three numbers
- 函数参数默认是常量。试图在函数体中更改参数值将会导致编译错误。这意味着你不能错误地更改参数值。
- 如果想要一个函数可以修改参数的值,并且想要在这些修改在函数调用结束后仍然存在,那么就应该把这个参数定义为输入输出参数(In-Out Parameters)。
- 定义一个输入输出参数时,在参数定义前加 inout 关键字。
- 当传入的参数作为输入输出参数时,需要在参数名前加&符,表示这个值可以被函数修改。
- 只能传递变量给输入输出参数。不能传入常量或者字面量(literal value),因为这些量是不能被修改的。
- 输入输出参数不能有默认值,不能是可变参数。
func swapTwoInts(inout a: Int, inout _ b: Int) {
let temporaryA = a
a = b
b = temporaryA
}
var someInt = 3
var anotherInt = 107
swapTwoInts(&someInt, &anotherInt)
print("someInt is now \(someInt), and anotherInt is now \(anotherInt)")
// prints "someInt is now 107, and anotherInt is now 3"
函数类型(Function Types)
- 每个函数都有种特定的函数类型,由函数的参数类型和返回类型组成。
- 在 Swift 中,使用函数类型就像使用其他类型一样。可以定义一个类型为函数的常量或变量,并将适当的函数赋值给它
- 函数类型可以作为另一个函数的参数类型。这样可以将函数的一部分实现留给函数的调用者来提供。
func addTwoInts(a: Int, _ b: Int) -> Int {
return a + b
}
func multiplyTwoInts(a: Int, _ b: Int) -> Int {
return a * b
}
var mathFunction: (Int, Int) -> Int = addTwoInts
print("Result: \(mathFunction(2, 3))")
// prints "Result: 5"
mathFunction = multiplyTwoInts
print("Result: \(mathFunction(2, 3))")
// prints "Result: 6"
func printMathResult(mathFunction: (Int, Int) -> Int, _ a: Int, _ b: Int) {
print("Result: \(mathFunction(a, b))")
}
printMathResult(addTwoInts, 3, 5)
// prints "Result: 8"
printMathResult(multiplyTwoInts, 3, 5)
// prints "Result: 15"
- 可以用函数类型作为另一个函数的返回类型。在返回箭头(->)后写一个完整的函数类型。
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
}
var currentValue = 3
let moveNearerToZero = chooseStepFunction(currentValue > 0)
// moveNearerToZero now refers to the stepBackward() function
print("Counting to zero:")
// Counting to zero:
while currentValue != 0 {
print("\(currentValue)... ")
currentValue = moveNearerToZero(currentValue)
}
print("zero!")
// 3...
// 2...
// 1...
// zero!
函数作为参数,作为返回值,是函数式编程的基础
嵌套函数(Nested Functions)
- 全局函数(global functions):定义在全局域中。
- 嵌套函数(nested functions):定义在别的函数体中。
- 默认情况下,嵌套函数是对外界不可见的,但是可以被它们的外围函数(enclosing function)调用。
- 一个外围函数也可以返回它的某一个嵌套函数,使得这个函数可以在其他域中被使用。
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)
// moveNearerToZero now refers to the nested stepForward() function
while currentValue != 0 {
print("\(currentValue)... ")
currentValue = moveNearerToZero(currentValue)
}
print("zero!")
// -4...
// -3...
// -2...
// -1...
// zero!