Swift的函数跟其它语言如C/Java是一样的, 都是由返回值、函数名称、函数参数等3要素组成。 区别是Swift使用关键字func来定义函数, func关键字类似于Python语言的def或者JavaScript的function。
在主流编程语言Java/C++/Object-C中定义函数, 是这个样子的:
返回值 函数名称(类型 参数1, 类型 参数2...) {
代码
}
//例如用Java写一个最简单的字符串判空函数
boolean hasStr(String value) {
if (value == null) {
return false;
}
if (value.length() == 0) {
return false;
} else {
return true;
}
}
//Swift是长这样的
func hasStr(value: String) -> Bool {
guard let tmp = value else {
return false
}
if value.isEmpty {
return true
} else {
return false
}
}
但在Swift里怎样做呢? 我觉得苹果肯定是脑洞大开了, 修改了定义函数的语法, 目前没搞明白苹果为什么这样做。Swift声明函数的语法长这样:
func 函数名称(参数1: 类型, 参数2: 类型 ...) -> 返回值类型 {
}
func关键字放在最前面, 返回值类型放在最后面, 使用->分隔参数和返回值类型。 看着有点别扭有没有? 下面看一下Swift和Java函数声明的区别:
func greet(person: String) -> String { //Swift写法
let greeting = "Hello, " + person + "!"
return greeting
}
public String greet(String person) { //Java写法
String tmp = "Hello" + person + "!";
return tmp;
}
在Java/C/Object-C语言里当函数无返回值时, 使用void作为返回值类型, 例如: public void greet(String person)。
在Swift语言中如果函数无返回值, 就不用写->和返回值类型了。例如:
func greet(person: String) { //省略->和返回值类型
print("Hello, \(person)!")
}
greet(person: "Dave") //注意函数调用时的参数赋值, 这个跟Object-C语法是一样的。
输出 Hello, Dave"
备注: 在Swift声明函数时func关键字、函数名称是必须有的, 函数参数、->和返回值类型是可选的!
前一篇Control Flow将到switch-case可以使用键值对(x, y)作为参数, Swift的函数返回值也可以,支持多个返回值(但Java/C/OC只能是一个变量或对象), 这些返回值参数可以在函数体内读写。 例如下面函数是得到一个数组中的最大数和最小数。说明: 下面函数是以2个参数为例, 还可以是3个、4个或者更多参数。
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]) //<strong><span style="color:#FF0000;">注意:Swift数组用[], Java/C/OC数组用{}</span></strong>
print("min is \(bounds.min) and max is \(bounds.max)")
// 输出 "min is -6 and max is 109"
还记得Swift的Optional类型吧, 就是像String? 、Int?这样在数据类型后面跟个问号, 表示它可能是nil。 当函数返回值可能有值或无值时, 就需要用Optional类型。 从而当函数体代码逻辑不满足时, 函数返回值是nil, 相当于Java的返回null。
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可能返回nil或者键值对(x, y), 所以要判断是否nil再引用。
if let bounds = minMax(array: [8, -6, 2, 109, 3, 71]) { //bounds不等于nil时执行函数体,即先判空再使用
print("min is \(bounds.min) and max is \(bounds.max)") //注意调用方法, .min和.max
}
// 输出"min is -6 and max is 109"
还记得switch-case里的下划线吗? 如果你不想每次调用函数时都写参数名称, 那么在声明函数时带上下划线。 语法如下:
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(1, secondParameterName: 2) //调用函数时省去了firstParameterName
说明:
像firstParameterName那样所有函数参数都加下划线, 就跟Java/C调用函数一样了, 不用写烦人的参数名称了(跟Object-C语法类似)。
Swift跟Java/C语言语法一样, 定义函数时可以给参数一个默认值, 当它是最后一个参数时, 在调用该函数时可以不写最后一个参数。 格式如下:
func 函数名称(类型: 参数1, 类型: 参数2 = 某个值, ...) -> 返回值 {
}
func someFunction(parameterWithoutDefault: Int, parameterWithDefault: Int = 12) {
// 可以省略最后一个参数parameterWithDefault, 但在函数体内它的值是12
}
someFunction(parameterWithoutDefault: 3, parameterWithDefault: 6) // parameterWithDefault是 6
someFunction(parameterWithoutDefault: 4) //<strong><span style="color:#FF0000;">只写1个参数,但第2个参数parameterWithDefault初值是12</span></strong>
当不确定函数参数有多少个时, 该怎么办? Java语法是这样写的
public void arithmeticMean(double ... values) {
for (double value:values) {
System.out.println(value);
}
}
arithmeticMean(0.0, 0.1, 0.2);
double[] group = {0.0, 0.1, 0.2};
arithmeticMean(group); //和arithmeticMean(0.0, 0.1, 0.2)执行结果一致!!!
备注:
Java使用...表示若干个参数, 其实就是个数组!
Swift语言同样使用...表示若干个参数(注意:这些参数必须是同一个数据类型!), 区别是Java使用冒号, Swift使用in遍历数组。
func arithmeticMean(_ numbers: Double...) -> Double { //numbers意义类似于Double型数组
var total: Double = 0
for number in numbers { //注意区别:Swift遍历用关键字in, Java是:
total += number
}
return total / Double(numbers.count)
}
arithmeticMean(1, 2, 3, 4, 5) //函数调用方式同Java/C, 因为声明函数时使用了下划线!
// 返回值3.0
arithmeticMean(3, 8.25, 18.75)
// 返回10.0
在Java语法里一般会要求将参数声明为常量final, 在函数体内不允许修改参数值; 但如果你非要修改的话, Java编译器也不会报错, 但是Java编码规范里要求不要改参数值!!! Java老司机是不会在函数体内修改参数值的。
如果你懂得C语言, 应该知道值引用的概念, 最典型的demo函数是交换2个int值, 即
void swap(int &a, int &b) {
int tmp = a;
a = b;
b = tmp;
}
在Swift语法里默认是不允许修改函数参数的, 但为了支持修改参数值, Swift提供了关键字inout, 作用跟C语言的引用&完全一样, 大概就是学的C语言吧。语法如下:
func swapTwoInts(_ a: inout Int, _ b: inout Int) { //参数类型前添加inout关键字,表示参数可修改!
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)")
// 输出"someInt is now 107, and anotherInt is now 3"
上面是Swift交换2个Int值的写法, 跟C语言的swap函数作用完全一样, 都要用&操作符,可以理解为值引用。
Function Types: Swift函数类型(类似于C语言的函数指针), 参数个数、类型完全一样而且返回值类型相同, 则函数名称可作为值赋给函数类型变量。
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 //mathFunction是函数类型
等价于
var mathFunction: (Int, Int) -> Int
mathFunction = addTwoInts
print("Result: \(mathFunction(2, 3))")
// 打印"Result: 5"
mathFunction = multiplyTwoInts
print("Result: \(mathFunction(2, 3))")
// 打印 "Result: 6"
说明: mathFuntion是个变量, 类型是函数。 mathFunction/addTwoInts/multiplyTwoInts的参数、返回值类型都一样, 所以可以将multipleTwoInts或者addTwoInts赋值给mathFunction。 用法跟C语言函数指针完全相同, 但我觉得实际编码中用处不大, 直接调用函数就好了, 为什么要用函数指针呢? 所以不建议使用该特性, 我写C/C++代码时就从没用过函数指针!
函数类型还可以用作函数参数类型, 即将函数指针传入函数体, 然并卵??? Swift开发这个特性干什么用? 在函数体内直接调用函数好不好, 脑洞大开也没想明白这个语法的好处!
func printMathResult(_ mathFunction: (Int, Int) -> Int, _ a: Int, _ b: Int) {
print("Result: \(mathFunction(a, b))")
}
printMathResult(addTwoInts, 3, 5)
// 输出"Result: 8"
备注: 我觉得知道Swift有这个语法就可以了,
在实际编码中不建议使用这个用法!
Swift既然能让函数类型当做参数, 那么当然也可以是返回值了。
func stepForward(_ input: Int) -> Int {
return input + 1
}
func stepBackward(_ input: Int) -> Int {
return input - 1
}
func chooseStepFunction(backward: Bool) -> (Int) -> Int { //标红部分表示是函数类型, 只有1个整型参数,返回值是整型。
return backward ? stepBackward : stepForward
}
var currentValue = 3
let moveNearerToZero = chooseStepFunction(backward: currentValue > 0)
// moveNearerToZero指向stepBackward() 函数
内部函数, 顾名思义在函数体内再定义函数, 语法和用法同全局函数, 在函数体外无法访问!
func chooseStepFunction(backward: Bool) -> (Int) -> Int { //chooseStepFunction是全局函数
func stepForward(input: Int) -> Int { return input + 1 } //stepForward是内部函数
func stepBackward(input: Int) -> Int { return input - 1 }
return backward ? stepBackward : stepForward
}
总结: Swift的函数跟其它语言的函数一样,都是为了执行一段代码和输出执行结果, 它参考了C语言的很多语法,区别是Swift定义函数的语法稍微有些差别, 新定义了关键字func; 在函数指针功能上, 更是跟C语言如初一辙。