Swift学习:2.6 函数
参考Swift 官方教程《The Swift Programming Language》中文版
函数(Functions)函数是用来完成特定任务的独立的代码块。你给一个函数起一个合适的名字,用来标识函数做什么,并且当函数需要执行的时候,这个名字会被“调用”。 Swift 统一的函数语法足够灵活,可以用来表示任何函数,包括从最简单的没有参数名字的 C 风格函数,到复杂的带局部和外部参数名的 Objective-C 风格函数。参数可以提供默认值,以简化函数调用。参数也可以既当做传入参数,也当做传出参数,也就是说,一旦函数执行结束,传入的参数值可以被修改。 在 Swift 中,每个函数都有一种类型,包括函数的参数值类型和返回值类型。你可以把函数类型当做任何其他普通变量类型一样处理,这样就可以更简单地把函数当做别的函数的参数,也可以从其他函数中返回函数。函数的定义可以写在在其他函数定义中,这样可以在嵌套函数范围内实现功能封装。 函数的定义与调用(Defining and Calling Functions)当你定义一个函数时,你可以定义一个或多个有名字和类型的值,作为函数的输入(称为参数,parameters),也可以定义某种类型的值作为函数执行结束的输出(称为返回类型)。 每个函数有个函数名,用来描述函数执行的任务。要使用一个函数时,你用函数名“调用”,并传给它匹配的输入值(称作实参,arguments)。一个函数的实参必须与函数参数表里参数的顺序一致。 在下面例子中的函数叫做 func sayHello(personName: String) -> String {
let greeting = "Hello," + personName + "!"
return greeting
}
所有的这些信息汇总起来成为函数的定义,并以 该定义描述了函数做什么,它期望接收什么和执行结束时它返回的结果是什么。这样的定义使的函数可以在别的地方以一种清晰的方式被调用: println(sayHello("Anna"))
// prints "Hello,Anna!"
println(sayHello("Brian"))
// prints "Hello,Brian!"
调用 在 你可以用不同的输入值多次调用 为了简化这个函数的定义,可以将问候消息的创建和返回写成一句: func sayHelloAgain(personName: String) -> String {
return "Hello again," + personName + "!"
}
println(sayHelloAgain("Anna"))
// prints "Hello again,Anna!"
函数参数与返回值(Function Parameters and Return Values)函数参数与返回值在Swift中极为灵活。你可以定义任何类型的函数,包括从只带一个未名参数的简单函数到复杂的带有表达性参数名和不同参数选项的复杂函数。 多重输入参数(Multiple Input Parameters)函数可以有多个输入参数,写在圆括号中,用逗号分隔。 下面这个函数用一个半开区间的开始点和结束点,计算出这个范围内包含多少数字: func halfOpenRangeLength(start: Int,end: Int) -> Int {
return end - start
}
println(halfOpenRangeLength(1,10))
// prints "9"
无参函数(Functions Without Parameters)函数可以没有参数。下面这个函数就是一个无参函数,当被调用时,它返回固定的 func sayHelloWorld() -> String {
return "hello,world"
}
println(sayHelloWorld())
// prints "hello,world"
尽管这个函数没有参数,但是定义中在函数名后还是需要一对圆括号。当被调用时,也需要在函数名后写一对圆括号。 无返回值函数(Functions Without Return Values)函数可以没有返回值。下面是 func sayGoodbye(personName: String) {
println("Goodbye,(personName)!")
}
sayGoodbye("Dave")
// prints "Goodbye,Dave!"
因为这个函数不需要返回值,所以这个函数的定义中没有返回箭头(->)和返回类型。
被调用时,一个函数的返回值可以被忽略: 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
第一个函数
多重返回值函数(Functions with Multiple Return Values)你可以用元组(tuple)类型让多个值作为一个复合值从函数中返回。 下面的这个例子中, 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"
需要注意的是,元组的成员不需要在函数中返回时命名,因为它们的名字已经在函数返回类型中有了定义。 函数参数名称(Function Parameter Names)以上所有的函数都给它们的参数定义了 func someFunction(parameterName: Int) {
// function body goes here,and can use parameterName
// to refer to the argument value for that parameter
}
但是,这些参数名仅在函数体中使用,不能在函数调用时使用。这种类型的参数名被称作 外部参数名(External Parameter Names)有时候,调用函数时,给每个参数命名是非常有用的,因为这些参数名可以指出各个实参的用途是什么。 如果你希望函数的使用者在调用函数时提供参数名字,那就需要给每个参数除了局部参数名外再定义一个 func someFunction(externalParameterName localParameterName: Int) {
// function body goes here,and can use localParameterName
// to refer to the argument value for that parameter
}
以下是个例子,这个函数使用一个 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"
使用外部参数名让第二个版本的
简写外部参数名(Shorthand External Parameter Names)如果你需要提供外部参数名,但是局部参数名已经定义好了,那么你不需要写两次参数名。相反,只写一次参数名,并用 下面这个例子定义了一个叫 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”
默认参数值(Default Parameter Values)你可以在函数体中为每个参数定义
以下是另一个版本的 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"
默认值参数的外部参数名(External Names for Parameters with Default Values)在大多数情况下,给带默认值的参数起一个外部参数名是很有用的。这样可以保证当函数被调用且带默认值的参数被提供值时,实参的意图是明显的。 为了使定义外部参数名更加简单,当你未给带默认值的参数提供外部参数名时,Swift 会自动提供外部名字。此时外部参数名与局部名字是一样的,就像你已经在局部参数名前写了 下面是 func join(s1: String,joiner: String = " ") -> String {
return s1 + joiner + s2
}
在这个例子中,Swift 自动为 join("hello",joiner: "-")
// returns "hello-world"
可变参数(Variadic Parameters)一个 传入可变参数的值在函数体内当做这个类型的一个数组。例如,一个叫做 下面的这个函数用来计算一组任意长度数字的算术平均数: 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
如果函数有一个或多个带默认值的参数,而且还有一个可变参数,那么把可变参数放在参数表的最后。 常量参数和变量参数(Constant and Variable Parameters)函数参数默认是常量。试图在函数体中更改参数值将会导致编译错误。这意味着你不能错误地更改参数值。 但是,有时候,如果函数中有传入参数的变量值副本将是很有用的。你可以通过指定一个或多个参数为变量参数,从而避免自己在函数中定义新的变量。变量参数不是常量,你可以在函数中把它当做新的可修改副本来使用。 通过在参数名前加关键字 func alignRight(var string: String,count: Int,pad: Character) -> String {
let amountToPad = count - countElements(string)
if amountToPad < 1 {
return string
}
let padString = String(pad)
for _ in 1...amountToPad {
string = padString + string
}
return string
}
let originalString = "hello"
let paddedString = alignRight(originalString,10,"-")
// paddedString is equal to "-----hello"
// originalString is still equal to "hello"
这个例子中定义了一个新的叫做
该函数首先计算出多少个字符需要被添加到
输入输出参数(In-Out Parameters)变量参数,正如上面所述,仅仅能在函数体内被更改。如果你想要一个函数可以修改参数的值,并且想要在这些修改在函数调用结束后仍然存在,那么就应该把这个参数定义为输入输出参数(In-Out Parameters)。 定义一个输入输出参数时,在参数定义前加 你只能将变量作为输入输出参数。你不能传入常量或者字面量(literal value),因为这些量是不能被修改的。当传入的参数作为输入输出参数时,需要在参数前加
下面是例子, func swapTwoInts(inout a: Int,inout b: Int) {
let temporaryA = a
a = b
b = temporaryA
}
这个 你可以用两个 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”
从上面这个例子中,我们可以看到
函数类型(Function Types)每个函数都有种特定的函数类型,由函数的参数类型和返回类型组成。 例如: func addTwoInts(a: Int,b: Int) -> Int {
return a + b
}
func multiplyTwoInts(a: Int,b: Int) -> Int {
return a * b
}
这个例子中定义了两个简单的数学函数: 这两个函数的类型是 下面是另一个例子,一个没有参数,也没有返回值的函数: func printHelloWorld() {
println("hello,world")
}
这个函数的类型是: 使用函数类型(Using Function Types)在 Swift 中,使用函数类型就像使用其他类型一样。例如,你可以定义一个类型为函数的常量或变量,并将函数赋值给它: var mathFunction: (Int,Int) -> Int = addTwoInts
这个可以读作: “定义一个叫做
现在,你可以用 println("Result: (mathFunction(2,3))")
// prints "Result: 5"
有相同匹配类型的不同函数可以被赋值给同一个变量,就像非函数类型的变量一样: mathFunction = multiplyTwoInts
println("Result: (mathFunction(2,3))")
// prints "Result: 6"
就像其他类型一样,当赋值一个函数给常量或变量时,你可以让 Swift 来推断其函数类型: let anotherMathFunction = addTwoInts
// anotherMathFunction is inferred to be of type (Int,Int) -> Int
函数类型作为参数类型(Function Types as Parameter Types)你可以用 下面是另一个例子,正如上面的函数一样,同样是输出某种数学运算结果: func printMathResult(mathFunction: (Int,Int) -> Int,a: Int,b: Int) {
println("Result: (mathFunction(a,b))")
}
printMathResult(addTwoInts,5)
// prints "Result: 8”
这个例子定义了 当
函数类型作为返回类型(Function Type as Return Types)你可以用函数类型作为另一个函数的返回类型。你需要做的是在返回箭头( 下面的这个例子中定义了两个简单函数,分别是 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
上面这个例子中计算出从 现在, println("Counting to zero:")
// Counting to zero:
while currentValue != 0 {
println("(currentValue)... ")
currentValue = moveNearerToZero(currentValue)
}
println("zero!")
// 3...
// 2...
// 1...
// zero!
嵌套函数(Nested Functions)这章中你所见到的所有函数都叫全局函数(global functions),它们定义在全局域中。你也可以把函数定义在别的函数体中,称作嵌套函数(nested functions)。 默认情况下,嵌套函数是对外界不可见的,但是可以被他们封闭函数(enclosing function)来调用。一个封闭函数也可以返回它的某一个嵌套函数,使得这个函数可以在其他域中被使用。 你可以用返回嵌套函数的方式重写 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! (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |