以前学习swift时的我的笔记,根据github:the-swift-programming-language-in-chinese学习、总结,将重要的内容提取,加以理解后整理为学习笔记,方便之后查询用。详细能够参考the-swift-programming-language-in-chinese,或者苹果官方英文版文档html
当前版本是swift2.2ios
func sayHello(personName: String, alreadyGreeted: Bool) -> String { if alreadyGreeted { return sayHelloAgain(personName) } else { return sayHello(personName) } }
函数参数都有一个外部参数名(external parameter name)和一个局部参数名(local parameter name)。外部参数名用于在函数调用时标注传递给函数的参数,局部参数名在函数的实现内部使用。git
func someFunction(firstParameterName: Int, secondParameterName: Int) { // function body goes here // firstParameterName and secondParameterName refer to // the argument values for the first and second parameters } someFunction(1, secondParameterName: 2)
通常状况下,第一个参数省略其外部参数名,第二个以及随后的参数使用其局部参数名做为外部参数名。全部参数必须有独一无二的局部参数名。尽管多个参数能够有相同的外部参数名,但不一样的外部参数名能让你的代码更有可读性。github
你能够在局部参数名前指定外部参数名,中间以空格分隔:swift
func someFunction(externalParameterName localParameterName: Int) { // function body goes here, and can use localParameterName // to refer to the argument value for that parameter }
若是你提供了外部参数名(包括局部参数名做为外部参数名的状况),那么函数在被调用时,必须使用外部参数名。若是想忽略外部参数名,使用_替代便可api
你能够在函数体中为每一个参数定义默认值(Deafult Values)。当默认值被定义后,调用这个函数时能够忽略这个参数。数组
func someFunction(parameterWithDefault: Int = 12) { } someFunction(6) // parameterWithDefault is 6 someFunction() // parameterWithDefault is 12
将带有默认值的参数放在函数参数列表的最后。这样能够保证在函数调用时,非默认参数的顺序是一致的,同时使得相同的函数在不一样状况下调用时显得更为清晰。不过不放在最后也是能够的闭包
一个可变参数(variadic parameter)能够接受零个或多个值。函数调用时,你能够用可变参数来指定函数参数能够被传入不肯定数量的输入值。经过在变量类型名后面加入(...)的方式来定义可变参数。app
可变参数的传入值在函数体中变为此类型的一个数组。例如,一个叫作 numbers 的 Double... 型可变参数,在函数体内能够当作一个叫 numbers 的 [Double] 型的数组常量。ide
// 求算数平均数 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) // 使用AnyObject就相似print函数了 func alvalible(num:AnyObject...) { print(num[0],num[1]) }
函数参数默认是常量。试图在函数体中更改参数值将会致使编译错误。
经过在参数名前加关键字 var 来定义变量参数:
func alignRight(var astring: String) -> String { astring += "123" return astring }
swift是值传递的,可变参数做用域只在函数内部,对调用者不产生影响,和C中的指针传递不同,若是想达到C指针的效果,可使用输入输出参数
变量参数,正如上面所述,仅仅能在函数体内被更改。若是你想要一个函数能够修改参数的值,而且想要在这些修改在函数调用结束后仍然存在,那么就应该把这个参数定义为输入输出参数(In-Out Parameters)。调用的时候实参必须可变,且加上&
func swapTwoInts(inout a: Int, inout _ b: Int) { let temporaryA = a a = b b = temporaryA } var someInt = 3 var anotherInt = 107 swapTwoInts(&someInt, &anotherInt)
输入输出参数不能有默认值,并且可变参数不能用 inout 标记。若是你用 inout 标记一个参数,这个参数不能被 var 或者 let 标记。
func addTwoInts(a: Int, _ b: Int) -> Int { return a + b } func printHelloWorld() { print("hello, world") }
第一个函数的类型是(Int, Int) -> Int
,能够解读为“这个函数类型有两个 Int 型的参数并返回一个 Int 型的值。”。第二个() -> Void
在 Swift 中,使用函数类型就像使用其余类型同样。例如,你能够定义一个类型为函数的常量或变量,并将适当的函数赋值给它:
var mathFunction: (Int, Int) -> Int = addTwoInts mathFunction(2, 3) // 直接使用
这个能够解读为:
“定义一个叫作 mathFunction 的变量,类型是‘一个有两个 Int 型的参数并返回一个 Int 型的值的函数’,并让这个新变量指向 addTwoInts 函数”。
就像其余类型同样,当赋值一个函数给常量或变量时,你可让 Swift 来推断其函数类型:
let anotherMathFunction = addTwoInts
参数为函数类型
func printMathResult(mathFunction: (Int, Int) -> Int, _ a: Int, _ b: Int) { print("Result: \\(mathFunction(a, b))") }
函数类型做为返回类型
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 }
嵌套函数(Nested Functions)
这章中你所见到的全部函数都叫全局函数(global functions),它们定义在全局域中。你也能够把函数定义在别的函数体中,称做嵌套函数(nested functions)。
默认状况下,嵌套函数是对外界不可见的,可是能够被它们的外围函数(被嵌套的函数即例中的chooseStepFunction
)调用。一个外围函数也能够返回它的某一个嵌套函数,使得这个函数能够在其余域中被使用。
你能够用返回嵌套函数的方式重写 chooseStepFunction(_:) 函数:
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 { print("\\(currentValue)... ") currentValue = moveNearerToZero(currentValue) } print("zero!") // -4... // -3... // -2... // -1... // zero!
闭包表达式语法有以下通常形式:
{ (parameters) -> returnType in statements }
闭包表达式语法可使用常量、变量和inout类型做为参数,不能提供默认值。也能够在参数列表的最后使用可变参数。元组也能够做为参数和返回值。
sort(_:)
方法接受一个闭包,该闭包函数须要传入与数组元素类型相同的两个值,并返回一个布尔类型值来代表当排序结束后传入的第一个参数排在第二个参数前面仍是后面。若是第一个参数值出如今第二个参数值前面,排序闭包函数须要返回true,反之返回false。sort函数会将数组里面的元素按照冒泡排序同样的返回给s1,s2两个参数,而后进行比较排序。
函数对应的闭包表达式版本的代码:
reversed = names.sort({ (s1: String, s2: String) -> Bool in return s1 > s2 })
然而在内联闭包表达式中,函数和返回值类型都写在大括号内,而不是大括号外。
闭包的函数体部分由关键字in引入。该关键字表示闭包的参数和返回值类型定义已经完成,闭包函数体即将开始。
由于排序闭包函数是做为sort(_:)
方法的参数传入的,Swift 能够推断其参数和返回值的类型。sort(_:)
方法被一个字符串数组调用,所以其参数必须是(String, String) -> Bool
类型的函数。这意味着(String, String)
和Bool类型并不须要做为闭包表达式定义的一部分。由于全部的类型均可以被正确推断,返回箭头(->)和围绕在参数周围的括号也能够被省略:
reversed = names.sort( { s1, s2 in return s1 > s2 } )
实际上任何状况下,经过内联闭包表达式构造的闭包做为参数传递给函数或方法时,均可以推断出闭包的参数和返回值类型。 这意味着闭包做为函数或者方法的参数时,您几乎不须要利用完整格式构造内联闭包。
单行表达式闭包能够经过省略return关键字来隐式返回单行表达式的结果,如上版本的例子能够改写为:
reversed = names.sort( { s1, s2 in s1 > s2 } )
在这个例子中,sort(_:)方法的第二个参数函数类型明确了闭包必须返回一个Bool类型值。由于闭包函数体只包含了一个单一表达式(s1 > s2),该表达式返回Bool类型值,所以这里没有歧义,return关键字能够省略。
Swift 自动为内联闭包提供了参数名称缩写功能,您能够直接经过$0,$1,$2来顺序调用闭包的参数,以此类推。
若是您须要将一个很长的闭包表达式做为最后一个参数传递给函数,可使用尾随闭包来加强函数的可读性。尾随闭包是一个书写在函数括号以后的闭包表达式,函数支持将其做为最后一个参数调用:
func someFunctionThatTakesAClosure(closure: () -> Void) { // 函数体部分 } // 如下是不使用尾随闭包进行函数调用 someFunctionThatTakesAClosure({ // 闭包主体部分 }) // 如下是使用尾随闭包进行函数调用 someFunctionThatTakesAClosure() { // 闭包主体部分 }
在闭包表达式语法一节中做为sort(_:)方法参数的字符串排序闭包能够改写为:
reversed = names.sort() { $0 > $1 }
若是函数只须要闭包表达式一个参数,当您使用尾随闭包时,您甚至能够把()省略掉:
reversed = names.sort { $0 > $1 }
map(_:)
函数,它接受一个具备一个参数和一个返回值的闭包,它会遍历sortArr数组的每个元素并将其赋给闭包参数,闭包的返回值将组成一个新的数组做为map函数的最终返回。新生产的数组元素与以前的数组一一对应
let sortArr = [1,2,3,4] let strArr = sortArr.map{ (temp) -> String in // 结果 strArr = ["4", "5", "6", "7"] return "\(temp + 3)" }
闭包能够在其被定义的上下文中捕获常量或变量。即便定义这些常量和变量的原做用域已经不存在,闭包仍然能够在闭包函数体内引用和修改这些值。
当一个闭包做为参数传到一个函数中,可是这个闭包在函数返回以后才被执行,咱们称该闭包从函数中逃逸。能够在参数名以前标注@noescape,用来指明这个闭包是不容许“逃逸”出这个函数的,即这个函数执行完成以后闭包就被释放了。若是强制给一个不容许“逃逸”的闭包赋值给全局变量则会编译错误
将闭包做为参数传递给函数时,你能得到一样的延时求值行为。
// customersInLine is ["Alex", "Ewa", "Barry", "Daniella"] func serveCustomer(customerProvider: () -> String) { print("Now serving \\(customerProvider())!") } serveCustomer( { customersInLine.removeAtIndex(0) } ) // prints "Now serving Alex!"
serveCustomer(_:)
接受一个返回顾客名字的显式的闭包。下面这个版本的serveCustomer(_:)
完成了相同的操做,不过它并无接受一个显式的闭包,而是经过将参数标记为@autoclosure来接收一个自动闭包。如今你能够将该函数当作接受String类型参数的函数来调用。customerProvider参数将自动转化为一个闭包,由于该参数被标记了@autoclosure特性。
// customersInLine is ["Ewa", "Barry", "Daniella"] func serveCustomer(@autoclosure customerProvider: () -> String) { print("Now serving \\(customerProvider())!") } serveCustomer(customersInLine.removeAtIndex(0)) // prints "Now serving Ewa!"
@autoclosure特性暗含了@noescape特性,若是你想让这个闭包能够“逃逸”,则应该使用@autoclosure(escaping)特性.