标签:
函数是完成指定任务的独立代码块。
Swift中的函数都有对应的类型,由参数类型和返回值类型共同组成。你可以向使用其他类型一样来使用函数类型,因此,可以将函数作为函数的参数,也可以将函数作为函数的返回值。函数中也可以嵌套函数,实现功能封装。
1、定义和调用函数
当你定义一个函数时,你可以定义一个或多个有名字和类型的值,作为函数的输入(参数,parameters),也可以定义某种类型的值作为函数执行结束的输出(返回类型)。
要使用一个函数时,你用函数名“调用”,并传给它相应的输入值(称作实参,arguments)。一个函数的实参必须与函数参数表里参数的顺序一致。
1 func sayHello(personName: String) -> String { 2 let greeting = "Hello, " + personName + "!" 3 return greeting 4 }
输入不同的参数,返回不同的结果:
1 print(sayHello("Anna")) 2 // prints "Hello, Anna!" 3 print(sayHello("Brian")) 4 // prints "Hello, Brian!"
为了简化这个函数的定义,可以将问候消息的创建和返回写成一句:
1 func sayHelloAgain(personName: String) -> String { 2 return "Hello again, " + personName + "!" 3 } 4 print(sayHelloAgain("Anna")) 5 // prints "Hello again, Anna!"
2、函数参数和返回值
(1)没有参数的函数
输入参数并不是必需的:
1 func sayHelloWorld() -> String { 2 return "hello, world" 3 } 4 print(sayHelloWorld()) 5 // prints "hello, world"
(2)有多个参数的函数
函数可以有多个参数,都写在括号里,并用逗号分隔。
1 func sayHello(personName: String, alreadyGreeted: Bool) -> String { 2 if alreadyGreeted { 3 return sayHelloAgain(personName) 4 } else { 5 return sayHello(personName) 6 } 7 } 8 print(sayHello("Tim", alreadyGreeted: true)) 9 // prints "Hello again, Tim!"
当调用含有一个或多个参数的函数时,第一个参数之后的其他参数都会用参数名作标识。
(3)没有返回值的函数
返回值并不是必需的:
1 func sayGoodbye(personName: String) { 2 print("Goodbye, \(personName)!") 3 } 4 sayGoodbye("Dave") 5 // prints "Goodbye, Dave!"
没有返回值,箭头和返回类型就不用写了。
注意:严格来说,即使没有定义返回值,函数也必须返回一个值。没有返回值的函数实际上返回了一种特殊的值Void,这是一个空的元组,实际上也就是没有元素的元组,可以写成()。
调用函数的时候,可以忽略它的返回值:
1 func printAndCount(stringToPrint: String) -> Int { 2 print(stringToPrint) 3 return stringToPrint.characters.count 4 } 5 func printWithoutCounting(stringToPrint: String) { 6 printAndCount(stringToPrint) 7 } 8 printAndCount("hello, world") 9 // prints "hello, world" and returns a value of 12 10 printWithoutCounting("hello, world") 11 // prints "hello, world" but does not return a value
注意:函数的返回值可以不被使用,但是函数必须声明它会返回一个值。如果函数定义了返回值类型,但在函数底部没有返回一个值,将会报编译时错误。
(4)有多个返回值的函数
如果有多个返回值,可以用元组来作为函数的返回类型。
1 func minMax(array: [Int]) -> (min: Int, max: Int) { 2 var currentMin = array[0] 3 var currentMax = array[0] 4 for value in array[1..<array.count] { 5 if value < currentMin { 6 currentMin = value 7 } else if value > currentMax { 8 currentMax = value 9 } 10 } 11 return (currentMin, currentMax) 12 }
由于元组的成员名已在返回类型中声明,可以用点语法来取出元组中对应的值。
1 let bounds = minMax([8, -6, 2, 109, 3, 71]) 2 print("min is \(bounds.min) and max is \(bounds.max)") 3 // prints "min is -6 and max is 109"
注意:元组的成员不需要在函数返回时命名,因为它们的名字已经在函数返回类型中有了定义。
----可选的元组返回类型
如果元组返回时,可能整个元组都没有值,那么,可以用可选元组来作为返回值类型,暗示返回的元组可能是nil。可选元组就是在元组的括号后面添加一个问号,例如(Int, Int)?或(String, Int, Bool)?。
注意:(Int, Int)?和(Int?, Int?)是不同的两个概念。可选元组是整个元组可能是nil,而不是各个成员的值可能是nil。
1 func minMax(array: [Int]) -> (min: Int, max: Int)? { 2 if array.isEmpty { return nil } 3 var currentMin = array[0] 4 var currentMax = array[0] 5 for value in array[1..<array.count] { 6 if value < currentMin { 7 currentMin = value 8 } else if value > currentMax { 9 currentMax = value 10 } 11 } 12 return (currentMin, currentMax) 13 }
可以用可选绑定来检查函数是否返回了元组:
1 if let bounds = minMax([8, -6, 2, 109, 3, 71]) { 2 print("min is \(bounds.min) and max is \(bounds.max)") 3 } 4 // prints "min is -6 and max is 109"
3、函数的参数名
函数的参数都有一个外部参数名和局部参数名。当调用函数时,外部参数名被用来标识参数。局部参数名则被用在函数的实现主体中。
1 func someFunction(firstParameterName: Int, secondParameterName: Int) { 2 // function body goes here 3 // firstParameterName and secondParameterName refer to 4 // the argument values for the first and second parameters 5 } 6 someFunction(1, secondParameterName: 2)
一般情况下,第一个参数省略其外部参数名,第二个以后的参数使用其局部参数名作为自己的外部参数名。所有参数需要有不同的局部参数名,尽管外部参数名可以是相同的,独特的外部参数名还是能让代码更具有可读性。
(1)指定外部参数名
可以在本地参数名前指定外部参数名,中间以空格分隔。
1 func someFunction(externalParameterName localParameterName: Int) { 2 // function body goes here, and can use localParameterName 3 // to refer to the argument value for that parameter 4 }
注意:如果提供了外部参数名,那么函数在被调用时,必须使用外部参数名。
下面的例子中有多个参数:
1 func sayHello(to person: String, and anotherPerson: String) -> String { 2 return "Hello \(person) and \(anotherPerson)!" 3 } 4 print(sayHello(to: "Bill", and: "Ted")) 5 // prints "Hello Bill and Ted!"
为每个参数指定外部参数名,在你调用函数sayHello(to:and:)
函数时两个参数都必须被标记出来。
(2)忽略外部参数名
如果你不想为第二个及后续的参数设置参数名,用下划线(_
)代替一个明确地参数名。
1 func someFunction(firstParameterName: Int, _ secondParameterName: Int) { 2 // function body goes here 3 // firstParameterName and secondParameterName refer to 4 // the argument values for the first and second parameters 5 } 6 someFunction(1, 2)
注意:第一个参数的外部名默认是省略的,所以 不必为它添加下划线。
4、默认参数值
当默认值被定义后,调用这个函数时可以忽略这个参数。
1 func someFunction(parameterWithDefault: Int = 12) { 2 // function body goes here 3 // if no arguments are passed to the function call, 4 // value of parameterWithDefault is 12 5 } 6 someFunction(6) // parameterWithDefault is 6 7 someFunction() // parameterWithDefault is 12
注意: 将带有默认值的参数放在函数参数列表的最后。这样可以保证在函数调用时,非默认参数的顺序是一致的,同时使得相同的函数在不同情况下调用时显得更为清晰。
5、可变参数
可变参数(variadic parameter)
可以接受零个或多个值。函数调用时,你可以用可变参数来传入不确定数量的输入参数。通过在变量类型名后面加入(...)
的方式来定义可变参数。
可变参数的传入值在函数体为此类型的一个数组。例如,一个 Double...
型可变参数numbers,在函数体内可以当做一个叫 numbers
的 [Double]
型的数组常量。
1 func arithmeticMean(numbers: Double...) -> Double { 2 var total: Double = 0 3 for number in numbers { 4 total += number 5 } 6 return total / Double(numbers.count) 7 } 8 arithmeticMean(1, 2, 3, 4, 5) 9 // returns 3.0, which is the arithmetic mean of these five numbers 10 arithmeticMean(3, 8.25, 18.75) 11 // returns 10.0, which is the arithmetic mean of these three numbers
注意:每个函数最多有一个可变参数。
6、常量和可变参数
函数的参数默认看做常量,在函数体内试图改变参数的值会报编译时错误。
但是,有时候,如果函数中有传入参数的变量值副本将是很有用的。你可以通过指定一个或多个参数为变量参数,避免自己在函数中定义新的变量。变量参数不是常量,你可以在函数中把它当做新的可修改副本来使用。
在参数名前加关键字 var
,定义变量参数:
1 func alignRight(var string: String, totalLength: Int, pad: Character) -> String { 2 let amountToPad = totalLength - string.characters.count 3 if amountToPad < 1 { 4 return string 5 } 6 let padString = String(pad) 7 for _ in 1...amountToPad { 8 string = padString + string 9 } 10 return string 11 } 12 let originalString = "hello" 13 let paddedString = alignRight(originalString, totalLength: 10, pad: "-") 14 // paddedString is equal to "-----hello" 15 // originalString is still equal to "hello"
注意: 对变量参数所进行的修改在函数调用结束后便消失了,并且对于函数体外是不可见的。变量参数仅仅存在于函数调用的生命周期中。
7、输入输出参数
变量参数仅仅能在函数体内被更改。如果你想要一个函数可以修改参数的值,并且想要在这些修改在函数调用结束后仍然存在,那么就应该把这个参数定义为输入输出参数(In-Out Parameters)。
定义一个输入输出参数时,在参数定义前加 inout
关键字。一个输入输出参数有传入函数的值,这个值被函数修改,然后被传出函数,替换原来的值。
只能将变量作为输入输出参数。不能传入常量或者字面量(literal value),因为这些量是不能被修改的。当传入的参数作为输入输出参数时,需要在参数前加&
符,表示这个值可以被函数修改。
注意: 输入输出参数不能有默认值,而且可变参数不能用 inout
标记。如果你用 inout
标记一个参数,这个参数不能被 var
或者 let
标记。
1 func swapTwoInts(inout a: Int, inout _ b: Int) { 2 let temporaryA = a 3 a = b 4 b = temporaryA 5 }
调用函数时在参数前加&符号:
1 var someInt = 3 2 var anotherInt = 107 3 swapTwoInts(&someInt, &anotherInt) 4 print("someInt is now \(someInt), and anotherInt is now \(anotherInt)") 5 // prints "someInt is now 107, and anotherInt is now 3"
注意: 输入输出参数和返回值是不一样的。上面的 swapTwoInts
函数并没有定义任何返回值,但仍然修改了 someInt
和 anotherInt
的值。输入输出参数是函数对函数体外产生影响的另一种方式。
8、函数类型
每个函数都有种特定的函数类型,由函数的参数类型和返回类型组成。
1 func addTwoInts(a: Int, _ b: Int) -> Int { 2 return a + b 3 } 4 func multiplyTwoInts(a: Int, _ b: Int) -> Int { 5 return a * b 6 }
上面的两个函数的函数类型都是(Int, Int) -> Int。
另一种函数:
1 func printHelloWorld() { 2 print("hello, world") 3 }
其返回类型是() -> Void。
(1)使用函数类型
函数类型的使用和其他类型一样,例如,可以把一个函数赋值给一个常量或变量。
1 var mathFunction: (Int, Int) -> Int = addTwoInts
这样,可以用mathFunction的名字来调用addTwoInts函数:
1 print("Result: \(mathFunction(2, 3))") 2 // prints "Result: 5"
同一函数类型的其他函数也可以赋值给这个变量:
1 mathFunction = multiplyTwoInts 2 print("Result: \(mathFunction(2, 3))") 3 // prints "Result: 6"
由于函数推断,可以不用显示声明变量的类型:
1 let anotherMathFunction = addTwoInts 2 // anotherMathFunction is inferred to be of type (Int, Int) -> Int
(2)函数类型作为参数类型
你可以用(Int, Int) -> Int
这样的函数类型作为另一个函数的参数类型。这样你可以将函数的一部分实现交由给函数的调用者。
1 func printMathResult(mathFunction: (Int, Int) -> Int, _ a: Int, _ b: Int) { 2 print("Result: \(mathFunction(a, b))") 3 } 4 printMathResult(addTwoInts, 3, 5) 5 // prints "Result: 8"
(3)函数类型作为返回类型
可以用函数类型作为另一个函数的返回类型。
例如,下面是两个简单函数。
1 func stepForward(input: Int) -> Int { 2 return input + 1 3 } 4 func stepBackward(input: Int) -> Int { 5 return input - 1 6 }
下面这个叫做 chooseStepFunction(_:)
的函数,它的返回类型是 (Int) -> Int
的函数。chooseStepFunction(_:)
根据布尔值 backwards
来返回 stepForward(_:)
函数或 stepBackward(_:)
函数:
1 func chooseStepFunction(backwards: Bool) -> (Int) -> Int { 2 return backwards ? stepBackward : stepForward 3 }
可以用chooseStepFunction(_:)
来获得一个函数:
1 var currentValue = 3 2 let moveNearerToZero = chooseStepFunction(currentValue > 0) 3 // moveNearerToZero now refers to the stepBackward() function
moveNearerToZero已获得了正确的函数,就可以用来将数字数到0:
1 print("Counting to zero:") 2 // Counting to zero: 3 while currentValue != 0 { 4 print("\(currentValue)... ") 5 currentValue = moveNearerToZero(currentValue) 6 } 7 print("zero!") 8 // 3... 9 // 2... 10 // 1... 11 // zero!
9、嵌套函数
1 func chooseStepFunction(backwards: Bool) -> (Int) -> Int { 2 func stepForward(input: Int) -> Int { return input + 1 } 3 func stepBackward(input: Int) -> Int { return input - 1 } 4 return backwards ? stepBackward : stepForward 5 } 6 var currentValue = -4 7 let moveNearerToZero = chooseStepFunction(currentValue > 0) 8 // moveNearerToZero now refers to the nested stepForward() function 9 while currentValue != 0 { 10 print("\(currentValue)... ") 11 currentValue = moveNearerToZero(currentValue) 12 } 13 print("zero!") 14 // -4... 15 // -3... 16 // -2... 17 // -1... 18 // zero!
标签:
原文地址:http://www.cnblogs.com/tt2015-sz/p/4865692.html