苹果Swift语言官方文档(中文翻译版)

本文档由长沙戴维营教育组织翻译和校对,由于英语水平有限,请大家指正。

长沙戴维营教育还为本教程录制了配套的视频教程在乌班图学院上免费提供,欢迎大家一起学习。

下面的章节,如果为蓝色链接表示以及翻译完毕,可以查看,如果为黑色则表示正在紧张的翻译中。本文档中文版每天都会更新,大家可以随时查看。如由Bug欢迎改正。


函数

函数是一个执行特定任务的自包含代码块。可以给函数指定一个名字来标识它,需要的时候通过名字“调用”它来执行任务。

Swift使用一个统一的语法来表示简单的C语言风格的函数到复杂的Objective-C语言风格的方法。函数参数可以有默认值,并且能够指定为输入输出(in-out)参数,在函数里进行修改。

每个Swift的函数都有一个类型,由它的参数类型和返回值类型决定。函数类型与其它Swift类型一样,可以用来声明变量、函数参数类型或者返回值类型等。Swift的函数可以嵌套定义。

函数的定义和调用

定义函数的时候,可以指定一个或多个输入参数和一个返回值类型。每个函数都有一个函数名来描述它的功能。通过函数名以及对应类型的参数值来调用这个函数。函数的参数传递的顺序必须与参数列表相同。

下面是一个叫greetingForPerson的函数,它接受一个人名作为输入,并返回对他的问候。为了实现这个函数,我们需要定义一个String类型的输入参数personName并且指定函数的返回值类型为String

  1. func sayHello(personName: String) -> String {
  2. let greeting = "Hello, " + personName + "!"
  3. return greeting
  4. }

上面就是一个以func关键字开头完整的函数定义。在函数名后用->来说明函数的返回值类型。这个定义描述了函数的功能、参数个数和类型以及返回值类型。函数的调用非常简洁:

  1. println(sayHello("Anna"))
  2. //prints "Helo, Anna!"
  3. println(sayHello("Brain"))
  4. //prints "Hello, Brain!"

在函数名后的圆括号里提供一个String类型的参数值来调用sayHello,如sayHello("Anna")sayHello返回一个String类型的值,因此可以之间将这个函数调用嵌入在println的调用中来打印它的返回结果。

sayHello中定义了一个String类型的常量greeting,并且将它设置为对personName的问候。然后通过return语句将greeting的值传递idao函数外面。一旦return greeting被执行,这个函数就会结束执行。

你可以调用sayHello函数多次,每次用不同的参数值。它会返回不同的问候语句。为了简化这个函数,可以将消息的创建和返回语句合并到同一行中。

  1. func sayHelloAgain(personName: String) -> String {
  2. return "Hello again, " + personName + "!"
  3. }
  4. println(sayHelloAgain("Anna"))
  5. //prints "Hello again, Anna!"

函数参数与返回值

Swift中函数参数与返回值的定义非常灵活。你可以定义只有一个非命名参数的工具函数,也可以定义具有说明性参数名字和不同参数选项的复杂函数。

多参数函数

函数可以有多个参数,在圆括号中用逗号隔开。下面的函数具有两个参数,并计算这个半闭区间的元素个数:

  1. func halfOpenRangeLength(start: Int, end: Int) -> Int {
  2. return end - start
  3. }
  4. println(halfOpenRangeLength(1, 10))
  5. //prints "9"

无参函数

函数可以没有输入参数。下面的函数每次调用的时候都返回同一个String类型的消息:

  1. func sayHelloWorld() -> String {
  2. return "hello, world"
  3. }
  4. println(sayHelloWorld())
  5. //prints "hello, world"

无参函数的调用和定义不能省略后面的圆括号。

无返回值的函数

Swift的函数返回值也不是必须的。下面是一个新的sayHello,每次都打印一个问候语句,而不是返回问候内容:

  1. func sayGoodbye(personName: String) {
  2. println("Goodbye, \(personName)!")
  3. }
  4. sayGoodbye("Dave")
  5. //prints "Goodbye, Dave!"

没有返回值的函数,后面不需要用->来说明返回值类型。

提示 严格来讲,sayGoodbye函数还是会返回一个值。对于没有定义返回值类型的函数,它都会返回一个Void类型的值。这是一个空的元组,可以写为()

函数调用的时候,可以忽略它的返回值:

  1. func printAndCount(stringToPrint: String) -> Int {
  2. println(stringToPrint)
  3. return countElements(stringToPrint)
  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

第一个函数printAndCount打印一个字符串,并且返回它的字符个数。第二个函数printWithoutCounting调用了第一个函数,但是将它的返回值忽略了。当调用第二个函数的时候,第一个函数还是会打印消息,但是它的返回值却没有被使用。

提示 虽然函数的返回值可以被忽略,但是如果一个函数定义的时候指明有返回值,则必须要返回一个值。否则的话会出现编译错误。

多个返回值的函数

通过元组可以在函数里一次性返回多个值。下面的count函数,会统计字符串中的元音、辅音和其它字符:

  1. func count(string: String) -> (vowels: Int, consonants: Int, others: Int) {
  2. var vowels = 0, consonants = 0, others = 0
  3. for character in string {
  4. switch String(character).lowercaseString {
  5. case "a", "e", "i", "o", "u":
  6. ++vowels
  7. case "b", "c", "d", "f", "g", "h", "j", "k", "l", "m",
  8. "n", "p", "q", "r", "s", "t", "v", "w", "x", "y", "z":
  9. ++consonants
  10. default:
  11. ++others
  12. }
  13. }
  14. return (vowels, consonants, others)
  15. }

用这个函数来统计任意字符串,并通过一个元组获取三个结果值:

  1. let total = count("some arbitray string!")
  2. println("\(total.vowels) vowels and \(total.consonants) consonants")
  3. //prints "6 vowels and 13 consonants"

注意,不需要再给元组的元素命名,它们会作为返回值的一部分返回。

函数的形参数名

上面所有的函数都为形参定义类名字:

  1. func someFunction(parameterName: Int) {
  2. //函数体,可以使用参数名称
  3. }

但是这些参数名只能在这个函数体中使用,而不能用在调用的时候。它们被称为本地参数名。

外部参数名

在函数调用的时候,如果能够使用参数名称,能够是代码更加具有可读性。外部参数就是用来完成这件事的:

  1. func someFunction(externalParametername localParameterName: Int) {
  2. //函数体,使用localParamterName来引用参数值
  3. }

提示 如果一个参数定义了外部参数名,在调用的时候就必须使用。

下面是关于本地参数名和外部参数名的示例:

  1. func join(s1: String, s2: String, joiner: String) -> String {
  2. return s1 + joiner + s2
  3. }
  4. join("hello", "world", ", ")
  5. //return s "hello, world"

如果使用外部参数名:

  1. func join(string s1: String, toString s2: String, withJoiner joiner: String) -> String {
  2. return s1 + joiner + s2
  3. }
  4. join(String: "hello", toString: "world", withJoiner: ", ")

简化外部参数名的定义

如果你需要同时给函数的参数提供外部参数名和本地参数名,但是想用相同的名字。戴维营教育可以在参数名前面添加#符号。Swift会将这个名字同时作为外部参数名和局部参数名。

  1. func containsCharacter(#string: String, #characterToFind: Character) -> Bool {
  2. for character in string {
  3. if character == characterToFind {
  4. return true
  5. }
  6. }
  7. return false
  8. }
  9. let containsAVee = containsCharacter(string: "aardvark", characterToFind: "v")

默认参数

函数定义的时候,可以给参数指定默认值,这样在调用的时候就可以省略不写。

提示 默认参数必须出现在参数列表的最后,并且在调用的时候必须按顺序赋值。

  1. func join(string s1: String, toString s2: String, withJoiner joiner:String = " ") -> String {
  2. return s1 + joiner + s2
  3. }
  4. join(string: "hello", toString: "world", withJoiner: "-")
  5. //returns "hello-world"
  6. join(string: "hello", toString: "world")
  7. //returns "hello world"

外部参数名与默认值

大多数情况下,为使用默认值的参数提供外部参数名能方便理解。如果你没有为它们提供外部参数名的话,Swift会自动为拥有默认值的参数提供与本地参数同名的外部参数名。

  1. func join(s1: String, s2: String, joiner: String = " ") -> String {
  2. return s1 + joiner + s2
  3. }
  4. join("hello", "world", joiner: "-")
  5. //returns "hello-world"

提示 这种情况可以使用_来代替显式的表示不需要外部参数名。

可变参数

可变参数可以接受0个或多个特定类型的值作为函数的参数。通过在参数类型后添加...表示可变参数。这些参数被作为数组传递到函数中。例如numbers: Double...在函数中表示一个叫numbersDouble[](数组)。

  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
  10. arithemeticMean(3, 8, 19)
  11. //returns 10.0

提示 一个函数最多只能有一个可变参数,并且必须出现在参数列表的最后。

常量参数与变量参数

函数参数默认为常量。在函数体中不能修改它们的值。可以使用var关键字将它们声明为变量。

  1. func alignRight(var string: String, count: Int, pad: Character) -> String {
  2. let amountToPad = count - countElements(string)
  3. for _ in 1...amountToPad {
  4. string = pad + string
  5. }
  6. return string
  7. }
  8. let originString = "hello"
  9. let paddedString = alignRight(orginalString, 10, "-")
  10. //paddedString is equal to "-----hello"
  11. //orginString is still equal to "hello"

上面的代码定义了一个叫alignRight的函数,它可以使输入的字符串有对齐,左边的空白用特定的占位符填充。它的string参数是一个局部变量,可以在函数体中进行操作。

提示 变量参数的作用范围为函数体,它并不会影响函数的外面的变量值。

输入输出参数

在上面提到,变量参数可以在函数里面进行修改,但对它的修改并不会影响函数外面。如果你想要修改函数外面的值,需要使用inout关键字它们定义为in-out参数。如果在函数里面修改了输入输出参数的值,同样会改变外面变量的值。在调用函数的时候,只能使用变量作为函数的实参,而不能使用常量和字面常量。在给输入输出函数传参时,需要在变量名前放置&符号来表示这个变量的值可能会被函数修改。

提示 输入输出参数不能够使用默认值和可变参数。同样,如果一个参数被标记为inout,就不能再使用varlet了。

  1. func swapTwoInts(inout a: Int, inout b: Int) {
  2. let temporaryA = a
  3. a = b
  4. b = temporaryA
  5. }

swapTwoInts实现了交换两个整型变量值的功能,下面是它的使用方法。

  1. var someInt = 3
  2. var anotherInt = 107
  3. swapTwoInts(&someInt, &anotherInt)
  4. println("someInt is now \(someInt), and anotherInt is now \(anotherInt)")
  5. //prints "someInt is now 107, and anotherInt is now 3"

提示 输入输出参数可以用来从函数里返回数据。

函数类型

每个函数都有一个特定的函数类型,由它的参数类型和返回值类型组成。例如:

  1. func addTwoInts(a: Int, b: Int) -> Int {
  2. return a + b
  3. }
  4. func multiplyTowInts(a: int, b: Int) -> Int {
  5. return a * b
  6. }

这个例子里定义了两个数学函数addTwoIntsmultiplyTwoInts。它们拥有相同的参数类型和返回值类型,因此它们的函数类型为(Int, Int) -> Int,读为: “一个拥有两个整型(Int)参数,并且返回值类型为整型(Int)的函数类型。”

下面是另外一个例子,它没有参数和返回值:

  1. func printHelloWorld() {
  2. println("hello, world")
  3. }

因此它的函数类型为() -> (),或者叫“一个没有参数并且返回值类型为void的函数类型”。没有声明返回值类型的函数返回值类型为Void,在Swift中等价与一个空的元组()

使用函数类型

在Swift中可以与其它类型一样使用函数类型。戴维营教育可以用它来定义常量、变量并且给它设置一个合适的函数。

  1. var mathFunction: (Int, Int) -> Int = addTwoInts

这个语句读做“定义一个mathFunction变量,它是一个函数类型,这个函数可以接受两个整型Int参数并且返回值为整型Int。使这个变量引用一个叫addTwoInts的函数”。

addTwoInts函数和mathFunction变量具有相同的数据类型。现在就可以通过刚才定义的变量名mathFunction来调用函数了:

  1. println("Result: \(mathFunction(2, 3))")
  2. //prints "Result: 5"

相同类型的函数可以赋值给同一个变量:

  1. mathFunction = multiplyTwoInts
  2. println("Result: \(mathFunction(2, 3))")
  3. //prints "Result: 6"

当然,你也可以让Swift自动替你推导变量或者常量的类型:

  1. let anotherMathFunction = addTwoInts
  2. //anotherMathFunction is inferred to be of type (Int, Int) -> Int

函数作为参数传递

你可以将函数类型如(Int, Int) -> Int作为另外一个函数的参数类型。这使你可以将函数的某些功能留给其它函数去实现。下面是一个例子:

  1. func printMathResult(mathFunction: (Int, Int) -> Int, a: Int, b: Int) {
  2. println("Result: \(mathFunction(a, b))")
  3. }
  4. printMathResult(addTwoInts, 3, 5)
  5. //prints "Result: 8"
  6. printMathResult(multiplyTwoInts, 3, 5)
  7. //prints "Result: 15"

函数作为返回值

函数还可以作为另外一个函数的返回值进行传递,只需要在->后写一个完整的函数类型。下面的例子定义了两个简单的函数stepForwardstepBackwardstepForward函数返回输入值加1的结果,而stepBackward返回输入值减1的结果。它们的函数类型都为(Int) -> Int

  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类型的函数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

上面的例子演示了根据currentValue的值来决定如何接近0。currentValue的初始值为3,大于0,因此chooseStepFunction返回stepBackward函数,并建起存放在moveNearerToZero常量中。

嵌套函数

到目前为止,我们所使用到的函数都是全局函数(global functions)。我们还可以在函数体里面定义函数,称为嵌套函数。

嵌套函数的作用域默认是它所在的函数体,但是可以作为返回值返回,然后在其它作用域中使用。下面我们重写chooseStepFunction,让它返回一个嵌套函数:

  1. func chooseStepFunction(backwards: Bool) -> (Int) -> Int {
  2. func stepForward(input: Int) -> Int {
  3. return input + 1
  4. }
  5. func stepBackward(input: Int) -> Int {
  6. return input - 1
  7. }
  8. return backwards ? stepBackward : stepForward
  9. }
  10. var currentValue = -4
  11. let moveNearerToZero = chooseStepFunction(currentValue > 0)
  12. //moveNearerToZero now refers to the nested stepForward() function
  13. while currentValue != 0 {
  14. println("\(currentValue)... ")
  15. currentValue = moveNearerToZero(currentValue)
  16. }
  17. println("zero!")
  18. // -4...
  19. // -3...
  20. // -2...
  21. // -1...
  22. // zero!

好吧,关于Swift语言的集合的学习,大茶哥只能帮你到这了。戴维营教育的伙计们,发奋图强吧。

戴维营教育网址:http://www.diveinedu.com Swift视频教程网址:http://www.ubuntucollege.cn