Swift的统一的功能语法足够灵活来表达任何东西,无论是甚至没有参数名称的简单的C风格的函数表达式,还是需要为每个本地参数和外部参数设置复杂名称的Objective-C语言风格的函数。参数提供默认值,以简化函数调用,并通过设置在输入输出参数,在函数执行完成时修改传递的变量。
Swift中的每个函数都有一个类型,包括函数的参数类型和返回类型。您可以方便的使用此类型像任何其他类型一样,这使得它很容易将函数作为参数传递给其他函数,甚至从函数中返回函数类型。函数也可以写在其他函数中来封装一个嵌套函数用以范围内有用的功能。
函数的声明与调用
当你定义一个函数时,你可以为其定义一个或多个命名,定义类型值作为函数的输入(称为参数),当该函数完成时将传回输出定义的类型(称为作为它的返回类型)。每一个函数都有一个函数名,用来描述了函数执行的任务。要使用一个函数的功能时,你通过使用它的名称进行“调用”,并通过它的输入值(称为参数)来匹配函数的参数类型。一个函数的提供的参数必须始终以相同的顺序来作为函数参数列表。
例如在下面的例子中被调用的函数greetingForPerson,像它描述的那样 -- 它需要一个人的名字作为输入并返回一句问候给那个人。
- func sayHello(personName: String) -> String {
- let greeting = "Hello," + personName + "!"
- return greeting
- }
该定义描述了函数的作用是什么,它期望接收什么,以及当它完成返回的结果是什么。该定义很容易让该函数可以让你在代码的其他地方以清晰、明确的方式来调用:
- println(sayHello("Anna"))
- // prints "Hello,Anna!"
- println(sayHello("Brian"))
- // prints "Hello,Brian!"
在sayHello的函数体开始定义了一个新的名为greeting的String常量,并将其设置加上personName个人姓名组成一句简单的问候消息。然后这个问候函数以关键字return来传回。只要问候函数被调用时,函数执行完毕是就会返回问候语的当前值。
你可以通过不同的输入值多次调用sayHello的函数。上面的例子显示了如果它以"Anna"为输入值,以"Brian"为输入值会发生什么。函数的返回在每种情况下都是量身定制的问候。
为了简化这个函数的主体,结合消息创建和return语句用一行来表示:
- func sayHello(personName: String) -> String {
- return "Hello again," + personName + "!"
- }
- println(sayHello("Anna"))
- // prints "Hello again,Anna!"
函数的参数和返回值
在swift中函数的参数和返回值是非常具有灵活性的。你可以定义任何东西无论是一个简单的仅仅有一个未命名的参数的函数还是那种具有丰富的参数名称和不同的参数选项的复杂函数。多输入参数
函数可以有多个输入参数,把他们写到函数的括号内,并用逗号加以分隔。下面这个函数设置了一个开始和结束索引的一个半开区间,用来计算在范围内有多少元素包含:
- func halfOpenRangeLength(start: Int,end: Int) -> Int {
- return end - start
- }
- println(halfOpenRangeLength(1,10))
- // prints "9"
无参函数
函数并没有要求一定要定义的输入参数。下面就一个没有输入参数的函数,任何时候调用时它总是返回相同的字符串消息:
- func sayHelloWorld() -> String {
- return "hello,world"
- }
- println(sayHelloWorld())
- // prints "hello,world"
没有返回值的函数
函数也不需要定义一个返回类型。这里有一个版本的sayHello的函数,称为waveGoodbye,它会输出自己的字符串值而不是函数返回:
- func sayGoodbye(personName: String) {
- println("Goodbye,\(personName)!")
- }
- sayGoodbye("Dave")
- // prints "Goodbye,Dave!"
提示:严格地说,sayGoodbye功能确实还返回一个值,即使没有返回值定义。函数没有定义返回类型但返 回了一个void返回类型的特殊值。它是一个简直是空的元组,实际上零个元素的元组,可以写为()。当一个函数调用时它的返回值可以忽略不计:
- func printAndCount(stringToPrint: String) -> Int {
- println(stringToPrint)
- return countElements(stringToPrint)
- }
- func printWithoutCounting(stringToPrint: String) {
- printAndCount(stringToPrint)
- }
- printAndCount("hello,world")
- // prints "hello,world" and returns a value of 12
- printWithoutCounting("hello,world" but does not return a value
提示:返回值可以忽略不计,但对一个函数来说,它的返回值即便不使用还是一定会返回的。在函数体底部 返回时与定义的返回类型的函数不能相容时,如果试图这样做将导致一个编译时错误。
多返回值函数
你可以使用一个元组类型作为函数的返回类型返回一个有多个值组成的一个复合作为返回值。下面的例子定义了一个名为count函数,用它计来算字符串中基于标准的美式英语中设定使用的元音、辅音以及字符的数量:
- func count(string: String) -> (vowels: Int,consonants: Int,others: Int) {
- var vowels = 0,consonants = 0,others = 0
- for character in string {
- switch String(character).lowercaseString {
- case "a","e","i","o","u":
- ++vowels
- case "b","c","d","f","g","h","j","k","l","m","n","p","q","r","s","t","v","w","x","y","z":
- ++consonants
- default:
- ++others
- }
- }
- return (vowels,consonants,others)
- }
- let total = count("some arbitrary string!")
- println("\(total.vowels) vowels and \(total.consonants) consonants")
- // prints "6 vowels and 13 consonants"
函数参数名
所有上面的函数都为参数定义了参数名称:
- func someFunction(parameterName: Int) {
- // function body goes here,and can use parameterName
- // to refer to the argument value for that parameter
- }
外部参数名
有时当你调用一个函数将每个参数进行命名是非常有用的,以表明你传递给函数的每个参数的目的。如果你希望用户函数调用你的函数时提供参数名称,除了设置本地地的参数名称,也要为每个参数定义外部参数名称。你写一个外部参数名称在它所支持的本地参数名称之前,之间用一个空格来分隔:
- func someFunction(externalParameterName localParameterName: Int) {
- // function body goes here,and can use localParameterName
- // to refer to the argument value for that parameter
- }
提示:如果您为参数提供一个外部参数名称,调用该函数时外部名称必须始终被使用。作为一个例子,考虑下面的函数,它通过插入他们之间的第三个"joiner"字符串来连接两个字符串:
- func join(s1: String,s2: String,joiner: String) -> String {
- return s1 + joiner + s2
- }
- join("hello","world",",")
- // returns "hello,world"
- func join(string s1: String,toString s2: String,withJoiner joiner: String) -> String {
- return s1 + joiner + s2
- }
现在,您可以使用这些外部参数名称调用清楚明确的调用该函数:
- join(string: "hello",toString: "world",withJoiner: ",world"
提示:考虑到使用外部参数名称的初衷就是为了在别人第一次阅读你的代码时并不知道你函数参数的目的是什么。 但当函数调用时如果每个参数的目的是明确的和毫不含糊的,你并不需要指定外部参数名称。
外部参数名称速记
如果你想为一个函数参数提供一个外部参数名,然而本地参数名已经使用了一个合适的名称了,你不需要为该参数写相同的两次名称。取而代之的是,写一次名字,并用一个hash符号(#)作为名称的前缀。这告诉Swift使用该名称同时作为本地参数名称和外部参数名称。这个例子定义了一个名为containsCharacter的函数,定义了两个参数的外部参数名称并通过放置一个散列标志在他们本地参数名称之前:
- func containsCharacter(#string: String,#characterToFind: Character) -> Bool {
- for character in string {
- if character == characterToFind { return true }
- }
- return false
- }
- let containsAVee = containsCharacter(string: "aardvark",characterToFind: "v")
- // containsAVee equals true,because "aardvark" contains a "v"
参数的默认值
可以为任何参数设定默认值来作为函数的定义的一部分。如果默认值已经定义,调用函数时就可以省略该参数的传值。提示:将使用默认值的参数放在函数的参数列表的末尾。这确保了所有调用函数的非默认参数使用相同的顺 序,并明确地表示在每种情况下相同的函数调用。这里有一个版本,是早期的join函数,并为参数joiner设置了默认值:
- func join(string s1: String,withJoiner joiner: String = " ") -> String {
- return s1 + joiner + s2
- }
- join(string: "hello",withJoiner: "-")
- // returns "hello-world"
- join(string: "hello",toString: "world")
- // returns "hello world"
有默认值的外部名称参数
在大多数情况下,为所有参数提供一个外部带有默认值的参数的名称是非常有用的(因此要求)。这将确如果当函数被调用时提供的值时参数必须具有明确的目的。为了使这个过程更容易,当你自己没有提供外部名称时,Swift自动为所有参数定义了缺省的参数外部名称。自动外部名称与本地名称相同,就好像你在你的代码中的本地名称之前写了一个hash符号。
这里有一个早期join函数版本,它不为任何参数提供的外部名称,但仍然提供了joiner参数的默认值:
- func join(s1: String,joiner: String = " ") -> String {
- return s1 + joiner + s2
- }
- join("hello",joiner: "-")
- // returns "hello-world"
提示:你可以通过编写一个下划线(_)有选择进行这种行为,而不是一个明确的定义外部参数名称。然 而,在适当情况下有默认值的外部名称参数总是优先被使用。
可变参数
一个可变参数的参数接受零个或多个指定类型的值。当函数被调用时,您可以使用一个可变参数的参数来指定该参数可以传递不同数量的输入值。写可变参数的参数时,需要参数的类型名称后加上点字符(...)。传递一个可变参数的参数的值时,函数体中是以提供适当类型的数组的形式存在。例如,一个可变参数的名称为numbers和类型为Double...在函数体内就作为名为numbers类型为Double[]的常量数组。
下面的示例计算任意长度的数字的算术平均值(也称为平均):
- 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,19)
- // returns 10.0,which is the arithmetic mean of these three numbers
提示:函数可以最多有一个可变参数的参数,而且它必须出现在参数列表的最后以避免多参数函 数调用时出现歧义。如果函数有一个或多个参数使用默认值,并且还具有可变参数,将可变参数放在列表的 最末尾的所有默认值的参数之后。
常量参数和变量参数
函数参数的默认值都是常量。试图改变一个函数参数的值会让这个函数体内部产生一个编译时错误。这意味着您不能错误地改变参数的值。但是,有时函数有一个参数的值的变量副本是非常有用的。您可以通过指定一个或多个参数作为变量参数,而不是避免在函数内部为自己定义一个新的变量。变量参数可以是变量而不是常量,并给函数中新修改的参数的值的提供一个副本。
在参数名称前用关键字var定义变量参数:
- func alignRight(var string: String,count: Int,pad: Character) -> String {
- let amountToPad = count - countElements(string)
- for _ in 1...amountToPad {
- string = pad + string
- }
- return string
- }
- let originalString = "hello"
- let paddedString = alignRight(originalString,10,"-")
- // paddedString is equal to "-----hello"
- // originalString is still equal to "hello"
该alignRight函数把输入参数的字符串定义成了一个变量参数。这意味着字符串现在可以作为一个局部变量,用传入的字符串值初始化,并且可以在函数体中进行相应操作。
函数首先找出有多少字符需要被添加到左边让字符串以右对齐在整个字符串中。这个值存储在本地常量amountToPad中。该函数然后将填充字符的amountToPad个字符拷贝到现有的字符串的左边,并返回结果。整个过程使用字符串变量参数进行字符串操作。
提示:一个变量参数的变化没有超出了每个调用函数,所以对外部函数体是不可见的。变量参数只能存在于函数调用 的生命周期里。
输入-输出参数
可变参数,如上所述,只能在函数本身内改变。如果你想有一个函数来修改参数的值,并且想让这些变化要坚持在函数调用结束后,你就可以定义输入-输出参数来代替。通过在其参数定义的开始添加inout关键字写用来标明输入-输出参数。一个在输入-输出参数都有一个传递给函数的值,由函数修改后,并从函数返回来替换原来的值。
参数列表中只可以传递一个变量作为一个in-out参数。不能传递一个常数或常值作为参数,因为常量和文字不能修改。你直接在变量名前放置一个连字符(&),当你把它作为一个参数传递给一个in-out参数,表明它可以通过该功能进行修改。
提示:in-out参数不能有默认值,可变参数的参数也不能被标记为inout。如果您标记参数为inout,它不能同时被标记为var或let。这里的一个叫做swapTwoInts函数,它有两个称为a和b的输入-输出整数参数:
- func swapTwoInts(inout a: Int,inout b: Int) {
- let temporaryA = a
- a = b
- b = temporaryA
- }
您可以调用交换函数swapTwoInts来交换任何int类型的变量以交换它们的值。需要注意的是他们传递给swapTwoInts执行功能时,someInt和anotherInt名称前需要加上的前缀符号:
- var someInt = 3
- var anotherInt = 107
- swapTwoInts(&someInt,&anotherInt)
- println("someInt is now \(someInt),and anotherInt is now \(anotherInt)")
- // prints "someInt is now 107,and anotherInt is now 3"
提示:输入输出参数与从函数返回的值是不一样的。上述swapTwoInts例子没有定义返回类型或返回一个值,但它仍然会修改someInt和anotherInt的值。输入输出参数是一个函数的另一个影响函数体范围之外的方式。
函数类型
每一个函数都有特定的函数类型,可以充当参数类型和函数的返回类型。例如:
- func addTwoInts(a: Int,b: Int) -> Int {
- return a + b
- }
- func multiplyTwoInts(a: Int,b: Int) -> Int {
- return a * b
- }
这两个函数的类型是(Int,Int)->Int。可以解读为:"这个函数类型,它有两个int型的参数,并返回一个int类型的值。"
下面是另一个例子,不带任何参数或返回值的函数:
- func printHelloWorld() {
- println("hello,world")
- }
使用函数类型
在swift中您可以像任何其他类型一样的使用函数类型。例如,你可以定义一个常量或变量为一个函数类型,并指定适当的函数给该变量:
- var mathFunction: (Int,Int) -> Int = addTwoInts
该addTwoInts函数具有与mathFunction相同类型的变量,所以这个赋值在能通过swift的类型检查。
现在你可以调用指定的函数名称为mathFunction:
- println("Result: \(mathFunction(2,3))")
- // prints "Result: 5"
- mathFunction = multiplyTwoInts
- println("Result: \(mathFunction(2,3))")
- // prints "Result: 6"
- let anotherMathFunction = addTwoInts
- // anotherMathFunction is inferred to be of type (Int,Int) -> Int
函数类型的参数
您可以使用一个函数类型,如(Int,Int)->Int作为另一个函数的参数类型。这使你预留了一个函数的某些方面的函数实现,让调用者提供的函数时被调用。下面就以打印上面的数学函数的结果为例:
- func printMathResult(mathFunction: (Int,Int) -> Int,a: Int,b: Int) {
- println("Result: \(mathFunction(a,b))")
- }
- printMathResult(addTwoInts,5)
- // prints "Result: 8"
当printMathResult被调用时,它传递addTwoInt函数,以及整数值3和5。它调用的值3和5所提供的功能,并打印8的结果。
printMathResult的作用是调用一个适当类型的数学函数并打印相应结果。那是什么功能的实现其实并不重要,你只要给以正确的类型匹配就行。这使printMathResult以调用者类型安全的方式转换了函数的功能。
函数类型的返回值
您可以使用一个函数类型作为另一个函数的返回类型。返回的函数-(>)即你的返回箭头后,立即写一个完整的函数类型就做到这一点。下面的例子定义了两个简单的函数调用stepForward和stepBackward。该stepForward函数返回一个值高于其输入值,而stepBackward函数返回一个值低于其输入值。这两个函数都有一个相同的类型(Int) -> Int:
- 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
如今moveNearerToZero执行了正确的功能,就可以用来计数到零:
- println("Counting to zero:")
- // Counting to zero:
- while currentValue != 0 {
- println("\(currentValue)... ")
- currentValue = moveNearerToZero(currentValue)
- }
- println("zero!")
- // 3...
- // 2...
- // 1...
- // zero!
嵌套函数
迄今为止所有你在本章中遇到函数都是全局函数,在全局范围内定义。其实你还可以在其他函数中定义函数,被称为嵌套函数。嵌套函数默认对外界是隐藏的,但仍然可以调用和使用其内部的函数。内部函数也可以返回一个嵌套函数,允许在嵌套函数内的另一个范围内使用。
你可以重写上面的chooseStepFunction例子使用并返回嵌套函数:
原文链接:https://www.f2er.com/swift/324930.html
- 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 {
- println("\(currentValue)... ")
- currentValue = moveNearerToZero(currentValue)
- }
- println("zero!")
- // -4...
- // -3...
- // -2...
- // -1...
- // zero!