函数是用来完成特定任务的独立的代码块。可以给函数起一个名字,用于标识一个函数,当函数需要执行的时候,这个名字就会用于"调用"函数。
在swift中,每个函数都有一种类型,包括函数的参数值类型和返回值类型。你可以把函数类型当做和其他普通变量类型一样处理,这就可以更简单的把函数当做其他的函数的参数,也可以从其他函数中返回函数。
一、函数定义与调用
- 函数的定义与调用。
func
是函数的关键字,参数是在函数名后的括号中,指定函数返回值类型时,用返回箭头->
后面跟着返回类型的方法是来表示。
/**
func前缀即表示为函数
函数名: sayHello
参数名: persionName,类型是String
返回值: 返回值是String类型的
*/
func sayHello(personName:String) -> String {
let getString = "hello," + personName;
return getString;
}
// 函数的调用
let str = sayHello("EndEvent");
print(str);
输出结果: hello,EndEvent
二、函数参数与返回值
- 无参函数,即函数可以是没有参数的:
func speak() -> String{
// 返回字符串
return "hello Swift!";
}
// 函数调用
print(speak());
输出结果: hello Swift!
- 多参函数,多个参数以
,
逗号分隔:
// 参数1: name; 参数2: age;
func sayHi(name:String, age:Int) -> String {
return "hi,我叫\(name),今年\(age)岁.";
}
print(sayHi("EndEvent", age: 20));
输出结果: hi,我叫EndEvent,今年20岁.
- 无返回值函数,即没有返回值:
func sayBye(name:String) {
print("Bye \(name)!");
}
sayBye("EndEvent");
// 输出结果: Bye EndEvent!
(备注: 虽然没有返回值定义,但实际`sayBye(_:)`函数依然是返回了值。这是一个特殊的返回值,叫`void`。其实返回是一个空的元组`tuple`,没有任何元素可以写成`()`)
- 多重返回值函数,可以用元组(
tuple
)类型让多个值作为一个复合值返回:
// 该函数中带3个参数,返回值是一个元组
func getMaxAndMinValue(a:Int, b:Int, c:Int) -> (max:Int, min:Int){
// 计算最大值的方法(系统自带)
let maxValue = max(a, b, c);
// 计算最小值的方法(系统自带)
let minValue = min(a, b, c);
return (maxValue,minValue);
}
let temp = getMaxAndMinValue(10, b: 3, c: 11);
// 因为元组成员值已命名,即可用点语法
print("maxValue:\(temp.max)");
print("minValue:\(temp.min)");
输出结果:
maxValue:11
minValue:3
- 可选元组返回类型。如果函数返回的元组类型,可能整个元组都是"空的",那么久可以使用* 可选的(Optional) *元组进行返回,这就表示整个元组是
nil
。例如(Int, Int)?
、(String, String)?
。
func getMaxAndMinValue(array: [Int]) -> (max: Int, min: 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 (currentMax, currentMin)
}
// 函数调用,不为空才打印输出
if let temp = getMaxAndMinValue([10,3,13,100,-50]) {
print("maxValue:\(temp.max)");
print("minValue:\(temp.min)");
}
输出结果:
maxValue:100
minValue:-50
注意: 可选元组类型如
(Int, Int)?
和 元组中包含可选类型如(Int?, Int?)
是不一样的。可选的元组类型,整个元组是可选的,而不是元组中的每个元组值。
三、函数参数名称
函数参数都有一个* 外部参数名 和 一个 局部参数名 *。外部参数名用于在函数调用时标注传递给函数的参数,内部参数名在函数的内部使用。
一般情况下,第一个参数省略其外部参数名,第二个以及随后的参数使用其局部参数名作为外部参数名。所有局部参数名必须是独一无二的。尽管多个参数可以有相同的外部参数名,但不同的外部参数名可以提高代码的可读性。
- 指定外部参数名
// firstName: 第一个参数的外部参数名
// name: 第一个参数的内部参数
func sayHello (firstName name:String) {
print("hello \(name)");
// 错误的,因为外部参数只用于标注传递
// print("hello \(firstName)");
}
// 有提供外部参数名,在调用时,必须使用外部参数名!!!
sayHello(firstName: "EndEvent");
输出结果: hello EndEvent
// 外部参数名和内部参数名可以是一样的
func sayHello (name name:String) {
print("hello \(name)");
}
sayHello(name: "EndEvent");
输出结果: hello EndEvent
// 所有外部参数名都可以是一样的,即都为name
// 内部参数名是要在函数内使用,所以必须是不同
func sayHello (name name1:String, name name2:String) {
print("hello \(name1)");
print("hello \(name2)");
}
sayHello(name: "EndEvent", name: "Swift");
输出结果:
hello EndEvent
hello Swift
- 忽略外部参数,如果不想为第二个以及后续的参数设置外部参数名,可以用
_
来代替一个明确的参数名:
// 第一个参数默认忽略其外部参数名称,显式写下划线是多余的
func sayHello (name1:String, _ name2:String) {
print("hello \(name1)");
print("hello \(name2)");
}
sayHello("EndEvent", "Swift");
输出结果:
hello EndEvent
hello Swift
- 默认参数值,即可以给函数体中每个参数定义
默认值
。如果有默认值,在调用的时候可以忽略此参数:
// 参数style是有默认值的
func goHome (name: String, style: String = "走路") {
print("\(name)是\(style)回家的");
}
goHome("EndEvent"); // 可以忽略style参数
goHome("Swift",style: "飞");
goHome("liming", style: "开车");
输出结果:
EndEvent是走路回家的
Swift是飞回家的
liming是开车回家的
注意: 将带有默认值的参数放在函数参数列表的最后,这可以保证在函数调用时,非默认参数的顺序的一致性,同时在相同函数在不同情况下调用时显得更为清晰。
- 可变参数,
可变参数
表示可以不接收或接收多个值。通过在变量类型们后加入...
的方法来定义可变参数:
// 计算平均值方式,参数是可变的
func arithmeticMean(numbers:Int...) -> Float {
var total:Float = 0;
var sum = 0;
for number in numbers {
sum += number;
}
total = Float(sum) / Float(numbers.count);
return total;
}
let total = arithmeticMean(1,2,3,4,5,6,7,8,9);
print(total);
输出结果: 5.0
注意: 一个函数中最多只能有一个可变参数。
- 常量参数和变量参数。函数参数默认是常量,试图在函数体重修改参数值这会导致编译出错。但有时候如果想修改参数值,那么久可以将参数定义为变量参数:
func myAppend(var str:String) -> String {
str.appendContentsOf(" --- haha");
return str;
}
print(myAppend("EndEvent"));
输出结果: EndEvent --- haha
注意: 对于变量参数,在函数调用结束后便会消失,即是变量参数仅仅存在于函数调用的生命周期中。
- 输入输出参数。如果想要在一个函数可以修改参数的值,并且在函数调用结束后仍然存在,即可以把这个参数定义为* 输入输出参数(In-Out Parameters) *
// 值的交换
func swapTwoInts(inout a:Int, inout b: Int) {
let tempValue = a;
a = b;
b = tempValue;
}
// 定义两个变量,并初始化
var a = 10;
var b = 30;
// 调用函数交换两个变量的值
swapTwoInts(&a, b: &b);
print("a = \(a)");
print("b = \(b)");
输出结果: a = 30 b = 10
注意:输入输出参数和返回值不一样,其实这就是将变量的地址传过去,在函数体中通过变量的地址进行修改值。
四、函数类型
每个函数都有特定的函数类型,由函数的参数类型和返回值类型组成。
- 使用函数类型。在swift中,使用函数类型就像使用其他类型一样:
// 相加函数
func sumFunc(a:Int, b:Int) -> Int {
return a + b;
}
// 相乘函数
func mathFunc(a:Int, b:Int) -> Int {
return a * b;
}
// 定义变量str,类型为(Int,Int) -> Int
var str:(Int,Int) -> Int = sumFunc;
// 调用相加函数
print("10 + 20 = \(str(10, 20))");
// 给str这个变量赋值一个函数
str = mathFunc;
// 调用相乘函数
print("10 * 20 = \(str(10, 20))");
输出结果: 10 + 20 = 30 10 * 20 = 200
- 函数类型作为参数类型。即你可以将(Int, Int) -> Int这样的函数类型作为另外一个函数的参数类型:
// 相乘函数
func mathFunc(a:Int, b:Int) -> Int {
return a * b;
}
// 输出函数
func printMathFuncResult(mathFunc:(Int, Int) -> Int, a:Int, b:Int){
print("\(a) * \(b) = \(mathFunc(a,b))");
}
// 调用输出函数
printMathFuncResult(mathFunc, a: 10, b: 10);
输出结果: 10 * 10 = 100
注意: 可能认为这和函数调用效果是一样,现在这是否多此一举?其实不是,
printMathFuncResult (_:_:_:)
函数作用是输出另外一个适当类型的数学函数的调用结果。即在这里只关心传入的函数类型是否正确,而不在意函数如何实现。printMathFuncResult (_:_:_:)
就是以一种安全类型(type-safe)
的方式,将部分功能转给调用者实现,也即是方便代码的封装。
- 函数类型作为返回类型。可以将函数类型作为另外一个函数的返回类型:
// 实现功能: 将currentInput值变为0的过程
var currentInput = -5;
// 加操作
func stepForward(input:Int) -> Int {
return input + 1;
}
// 减操作
func stepBackward(input:Int) -> Int {
return input - 1;
}
// 函数选择,参数为input,返回值为'(Int) -> Int'类型
func chooseStepFunction(isBackward:Bool) -> (Int) -> Int {
// YES:即表示currentInput值是大于0的,选择stepBackward减操作
// NO: 即表示currentInput值是小于0的,即选择stepForward加操作
return isBackward ? stepBackward : stepForward;
}
// 循环操作,直到currentInput为0
while currentInput != 0 {
print("currentInput: \(currentInput)");
// 根据currentInput值,选择对应操作的函数
var moveNearerToZero = chooseStepFunction(currentInput > 0);
// 调用操作
currentInput = moveNearerToZero(currentInput);
}
print("结束操作:\(currentInput)");
输出结果:
currentInput: -5
currentInput: -4
currentInput: -3
currentInput: -2
currentInput: -1
结束操作:0
五、嵌套函数
在本节文章中你说见到函数都是* 全局函数(global functions) ,它们都是属于全局域的。但你也可以将函数定义在函数体中,而这种称之为 嵌套函数(nested functions) 。
嵌套函数 ,在默认情况下对外界是不可见的,但却可以被它们的 外围函数(enclosing function) *调用。并且外围函数也可以返回其所嵌套的函数,使得这个函数也可以在其他域中被调用。
// 实现功能: 输入一个值,将值变为0的过程
var currentInput = -5;
// 函数选择 - 全局函数
func chooseStepFunction(isBackwark:Bool) -> (Int) -> Int {
// 加操作 - 嵌套函数
func stepForward(input:Int) -> Int {
return input + 1;
}
// 减操作 - 嵌套函数
func stepBackward(input:Int) -> Int {
return input - 1;
}
return isBackwark ? stepBackward : stepForward;
}
// 即是接受'(Int) -> Int' 类型的函数
let moveNearerToZero = chooseStepFunction(currentInput > 0);
// 循环操作,直到currentInput为0
while currentInput != 0 {
print("currentInput: \(currentInput)");
currentInput = moveNearerToZero(currentInput);
}
print("结束操作:\(currentInput)");
输出结果:
currentInput: -5
currentInput: -4
currentInput: -3
currentInput: -2
currentInput: -1
结束操作:0