Swift5.5学习笔记五:函数(Functions)
函数(Functions)
函数是执行特定任务的自包含代码块。
你给一个函数一个名字来标识它的作用,这个名字用于在需要时“调用”函数来执行它的任务
//一、定义和调用函数
//定义函数时,可以选择定义一个或多个类型的值并命名,函数把它作为入参,也就是函数的参数
//还可以选择定义函数在完成时输出传回的值类型,称为返回类型
func greet(person: String) -> String {
let greeting = "Hello, " + person + "!"
return greeting
}
print(greet(person: "Anna"))
// Prints "Hello, Anna!"
print(greet(person: "Brian"))
// Prints "Hello, Brian!"
//为了使这个函数的主体更短,您可以将消息创建和返回语句合并为一行:
func greetAgain(person: String) -> String {
return "Hello again, " + person + "!"
}
print(greetAgain(person: "Anna"))
// Prints "Hello again, Anna!"
//二、函数参数和返回值
//1.没有参数的函数
//函数不需要定义输入参数。
//这是一个没有输入参数的函数,无论何时调用它总是返回相同的String消息:
func sayHelloWorld() -> String {
return "hello, world"
}
print(sayHelloWorld())
// Prints "hello, world"
//2.具有多个参数的函数
//函数可以有多个输入参数,这些参数写在函数的括号内,用逗号分隔
func greetMutipleParmeters(person: String, alreadyGreeted: Bool) -> String {
if alreadyGreeted {
return greetAgain(person: person)
} else {
return greet(person: person)
}
}
print(greetMutipleParmeters(person: "Tim", alreadyGreeted: true))
// Prints "Hello again, Tim!"
//3.没有返回值的函数
//函数不需要定义返回类型
func greetNoReturn(person: String) {
print("Hello, \(person)!")
}
greetNoReturn(person: "Dave")
// Prints "Hello, Dave!"
//备注:因为它不需要返回值,所以函数的定义不包括返回箭头(->)或返回类型
//备注:严格地说,这个版本的函数功能即使没有定义返回值,确实还是返回了一个值。
//没有定义返回类型的函数返回一个特殊的type值Void。这只是一个空元组,写为()
//函数的返回值在调用时可以忽略:
func printAndCount(string: String) -> Int {
print(string)
return string.count
}
func printWithoutCounting(string: String) {
let _ = printAndCount(string: string)
}
printAndCount(string: "hello, world")
// prints "hello, world" and returns a value of 12
printWithoutCounting(string: "hello, world")
// prints "hello, world" but doesn't return a value
//4.具有多个返回值的函数
//您可以使用元组类型作为函数的返回类型,以将多个值作为一个复合返回值的一部分返回
//下面的示例定义了一个名为minMax(array:)的函数,该函数在Int值数组中查找最小和最大数字
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, -6, 2, 109, 3, 71])
print("min is \(bounds.min) and max is \(bounds.max)")
// Prints "min is -6 and max is 109"
//5.可选的元组返回类型
//如果从函数返回的元组类型有可能没有值,则可以使用可选的元组返回类型来反映整个元组可以是nil
//您可以通过在元组类型的右括号后放置一个问号来编写可选的元组返回类型
//例如 (Int, Int)?
//上面的minMax(array:)函数返回一个包含两个Int值的元组。但是,该函数不会对其传递的数组执行任何安全检查。
//如果array参数包含一个空数组,则上面定义的函数minMax(array:)将在尝试访问array[0]时触发运行时错误。
//要安全地处理空数组,编写函数minMax(array:)使用可选的元组返回类型,并在数组为空时返回一个nil值
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)
}
//可以使用可选绑定来检查minMax(array:)函数是否返回实际的元组值或nil
if let bounds = minMax(array: [8, -6, 2, 109, 3, 71]) {
print("min is \(bounds.min) and max is \(bounds.max)")
}
// Prints "min is -6 and max is 109"
//6.带有隐式返回的函数
//如果函数的整个主体是单个表达式,则该函数会隐式返回该表达式
func greeting(for person: String) -> String {
"Hello, " + person + "!"
}
print(greeting(for: "Dave"))
// Prints "Hello, Dave!"
func anotherGreeting(for person: String) -> String {
return "Hello, " + person + "!"
}
print(anotherGreeting(for: "Dave"))
// Prints "Hello, Dave!"
//二、函数参数标签和参数名称
//每个函数参数都有一个参数标签和一个参数名称。
//调用函数时使用参数标签;每个参数都写在函数调用中,在它之前有它的参数标签。参数名称用于函数的实现。
//默认情况下,参数使用它们的参数名称作为它们的参数标签。
func someFunction(firstParameterName: Int, secondParameterName: Int) {
// In the function body, firstParameterName and secondParameterName
// refer to the argument values for the first and second parameters.
}
someFunction(firstParameterName: 1, secondParameterName: 2)
//1.指定参数标签
//在参数名称之前写一个参数标签,用空格分隔:
func someFunction(argumentLabel parameterName: Int) {
// In the function body, parameterName refers to the argument value
// for that parameter.
}
//下面是这个greet(person:)函数的一个变体,它接受一个人的名字和家乡并返回一个问候语:
func greet(person: String, from hometown: String) -> String {
return "Hello \(person)! Glad you could visit from \(hometown)."
}
print(greet(person: "Bill", from: "Cupertino"))
// Prints "Hello Bill! Glad you could visit from Cupertino."
//使用参数标签可以让函数以一种富有表现力的类似句子的方式被调用,同时仍然提供一个可读且意图清晰的函数体。
//2.省略参数标签
//如果您不需要参数的参数标签,请为该参数编写下划线(_)而不是显式参数标签
//如果参数有参数标签,则在调用函数时必须使用参数标签
func someFunction(_ firstParameterName: Int, secondParameterName: Int) {
// In the function body, firstParameterName and secondParameterName
// refer to the argument values for the first and second parameters.
print("省略参数标签")
}
someFunction(1, secondParameterName: 1)
//3.默认参数值
//您可以为函数中的任何参数定义默认值,使用方法是在该参数的类型之后为该参数分配一个值。
//如果定义了默认值,则可以在调用函数时省略该参数。
func someFunction(parameterWithoutDefault: Int, parameterWithDefault: Int = 12) {
// If you omit the second argument when calling this function, then
// the value of parameterWithDefault is 12 inside the function body.
print("parameterWithoutDefault is \(parameterWithoutDefault) and parameterWithDefault is \(parameterWithDefault)")
}
someFunction(parameterWithoutDefault: 3, parameterWithDefault: 6) // parameterWithDefault is 6
someFunction(parameterWithoutDefault: 4) // parameterWithDefault is 12
//将没有默认值的参数放在函数参数列表的开头,有默认值的参数之前。
//没有默认值的参数通常对函数的意义更重要,首先编写它们可以在调用的同一个函数的时候更容易地识别正,而有默认值参数可以被或略
//4.可变参数
//可变参数接受具有指定类型的多个或多个值。
//您可以使用可变参数来指定在调用函数时可以向参数传递不同数量的输入值。通过在参数的类型名称后插入三个句点字符(...)来编写可变参数
//传递给可变参数的值在函数体内作为适当类型的数组使用
//一个函数可以有多个可变参数。可变参数后面的第一个参数必须有一个参数标签
func arithmeticMean(_ numbers: Double...) -> Double {
var total: Double = 0
for number in numbers {
total += number
}
return total / Double(numbers.count)
}
print(arithmeticMean(1,2,3,4))
// returns 3.0, which is the arithmetic mean of these five numbers
print(arithmeticMean(3, 8.25, 18.75))
// returns 10.0, which is the arithmetic mean of these three numbers
//5.输入输出参数
//函数参数默认为常量。尝试从函数体内更改函数参数的值会导致编译时错误。
//如果您希望函数可以修改参数的值,并且希望这些更改在函数调用结束后保持不变,请将该参数定义为输入输出参数。
//您可以通过将inout关键字放在参数类型之前来编写输入输出参数
//输入输出参数不能有默认值,可变参数不能标记为inout。
//下面是一个名为swapTwoInts(::)的函数示例,它有两个名为a和b的整数输入输出参数
func swapTwoInts(_ a: inout Int, _ b: inout 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"
//您可以使用两个Int类型的变量调用该函数swapTwoInts(::)来交换它们的值。
//请注意,当它们传递给函数时,someInt和anotherInt以&符号为前缀
//备注:输入输出参数与从函数返回值不同。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
//1.使用函数类型
//您可以像使用 Swift 中的任何其他类型一样使用函数类型。
//例如,您可以将常量或变量定义为函数类型,并为该变量分配适当的函数:
var mathFunction: (Int, Int) -> Int = addTwoInts
//这可以理解为:定义一个名为mathFunction的变量,它的类型是‘一个接受两个Int值并返回一个Int值的函数。’ 设置这个新变量来引用被调用的函数addTwoInts。
print("Result: \(mathFunction(2, 3))")
// Prints "Result: 5"
//可以将具有相同匹配类型的不同函数分配给相同的变量,与非函数类型相同:
mathFunction = multiplyTwoInts
print("Result: \(mathFunction(2, 3))")
// Prints "Result: 6"
//与任何其他类型一样,当您将函数分配给常量或变量时,您可以让 Swift 来推断函数类型:
let anotherMathFunction = addTwoInts
// anotherMathFunction is inferred to be of type (Int, Int) -> Int
//2.函数类型作为参数类型
//您可以使用函数类型,这使您可以将函数实现的某些方面留给函数调用者在调用函数时提供。
//这是一个打印上述数学函数结果的示例:
func printMathResult(_ mathFunction: (Int, Int) -> Int, _ a: Int, _ b: Int) {
print("Result: \(mathFunction(a, b))")
}
printMathResult(addTwoInts, 3, 5)
// Prints "Result: 8"
//3.函数类型作为返回类型
//您可以使用一个函数类型作为另一个函数的返回类型。
//您可以在返回函数的返回箭头(->)之后立即编写一个完整的函数类型
//一下这两个函数都有一个类型:(Int) -> Int
func stepForward(_ input: Int) -> Int {
return input + 1
}
func stepBackward(_ input: Int) -> Int {
return input - 1
}
//以下为函数chooseStepFunction(backward:)返回类型为(Int) -> Int
//它根据一个值为Boolean参数名为backward的参数,决定它的 返回函数stepBackward或者stepForward
func chooseStepFunction(backward: Bool) -> (Int) -> Int {
return backward ? stepBackward : stepForward
}
//您现在可以使用chooseStepFunction(backward:)函数来获取将朝一个方向或另一个方向步进的函数:
var currentValue = 3
let moveNearerToZero = chooseStepFunction(backward: currentValue > 0)
// moveNearerToZero now refers to the stepBackward() function
//现在moveNearerToZero可以用来计数到零:
print("Counting to zero:")
// Counting to zero:
while currentValue != 0 {
print("\(currentValue)... ")
currentValue = moveNearerToZero(currentValue)
}
print("zero!")
// 3...
// 2...
// 1...
// zero!
//四、嵌套函数
//到目前为止,您在本章中遇到的所有函数都是在全局范围内定义的全局函数的示例。
//您还可以在其他函数的主体内定义函数,称为嵌套函数。
//您可以重写上面的示例chooseStepFunction(backward:)函数以使用和返回嵌套函数
func chooseStepFunction(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 currentValue = -4
let moveNearerToZero = chooseStepFunction(backward: 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!