专注收集记录技术开发学习笔记、技术难点、解决方案
网站信息搜索 >> 请输入关键词:
您当前的位置: 首页 > Swift

从 Playgrounds 论 Swift(七): 闭包(Closures)

发布时间:2011-06-30 07:29:21 文章来源:www.iduyao.cn 采编人员:星星草
从 Playgrounds 论 Swift(7): 闭包(Closures)
转载请声明出处:http://blog.csdn.net/jinnchang/article/details/43268891

1、概念

闭包是一个自包含的功能模块,可以在代码中被传递和使用。
闭包可以捕获和存储其所在上下文中任意常量和变量的引用。Swift 会为你管理在捕获过程中涉及到的内存操作。

2、闭包的三种形式

  • 全局函数(有函数名,不会捕获任何值)
  • 嵌套函数(有函数名,可以在其封闭的函数中捕获值)
  • 闭包表达式(没有名字,利用轻量级的语法在其围绕的上下文中捕获值)
// 1、全局函数实现闭包
let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
func backwards(s1: String, s2: String) -> Bool {
    return s1 > s2
}
var reversed = sorted(names, backwards)

// 2、嵌套函数实现闭包
func makeIncrementor(forIncrement amount: Int) -> () -> Int {
    var runningTotal = 0
    func incrementor() -> Int {
        runningTotal += amount
        return runningTotal
    }
    return incrementor
}

// 3、闭包表达式实现闭包
reversed = sorted(names, { (s1: String, s2: String) -> Bool in return s1 > s2 } )

3、闭包表达式

(1)语法形式
{ (parameters) -> return type in
    statements
}
(2)闭包表达式的优化
  • 利用上下文推断参数和返回值类型
  • 单行闭包表达式可以省略 return 关键字
  • 参数名简写(Swift 自动为内联闭包提供了参数名称简写功能,你可以直接通过 $0,$1,$2 等名字来引用的闭包的参数的值)
  • 尾随闭包
// 1、原始方式
let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
func backwards(s1: String, s2: String) -> Bool {
    return s1 > s2
}
var reversed = sorted(names, backwards)

// 2、闭包表达式
reversed = sorted(names, { (s1: String, s2: String) -> Bool in return s1 > s2 } )

// 3、闭包表达式利用上下文推断参数和返回值类型
reversed = sorted(names, { s1, s2 in return s1 > s2 } )

// 4、闭包表达式单行可以省略 return
reversed = sorted(names, { s1, s2 in s1 > s2 } )

// 5、闭包表达式参数名简写
reversed = sorted(names, { $0 > $1 } )

// 6、闭包表达式运算符函数
reversed = sorted(names, >)

// 7、尾随闭包方式
reversed = sorted(names) { $0 > $1 }
注意:在最新的 Xcode 版本中运行上述代码会有部分语句识别不了">"的情况,报ambiguous use the operator 错误,这很可能是 Xcode 或者 Swift 暂时还不稳定造成,与语法本身无关。

4、尾随闭包(Trailing Closures)

如果你需要将一个很长的闭包表达式作为最后一个参数传递给函数,可以使用尾随闭包来增强函数的可读性。
尾随闭包是一个书写在函数括号之外的闭包表达式,函数支持将其作为最后一个参数调用。
注意:如果函数只有闭包表达式一个参数,当你使用尾随闭包时,你甚至可以把“()”省略掉。

let digitNames = [
    0: "Zero", 1: "One", 2: "Two",   3: "Three", 4: "Four",
    5: "Five", 6: "Six", 7: "Seven", 8: "Eight", 9: "Nine"
]
let numbers = [16, 58, 510]
let strings = numbers.map {
    (var number) -> String in
    var output = ""
    while number > 0 {
        output = digitNames[number % 10]! + output
        number /= 10
    }
    return output
}
println(strings)
// prints "["OneSix", "FiveEight", "FiveOneZero"]"

5、捕获(Caputure)

闭包可以在其定义的上下文中捕获常量或变量。
即使定义这些常量和变量的原作用域已经不存在,闭包仍然可以在闭包函数体内引用和修改这些值。

func makeIncrementor(forIncrement amount: Int) -> () -> Int {
    var runningTotal = 0
    func incrementor() -> Int {
        runningTotal += amount
        return runningTotal
    }
    return incrementor
}
let incrementByTen = makeIncrementor(forIncrement: 10)
incrementByTen()			// 10
incrementByTen()			// 20
let incrementBySeven = makeIncrementor(forIncrement: 7)
incrementBySeven()			// 7
incrementByTen()			// 30
incrementor 函数并没有任何参数,但是在函数体内访问了 runningTotal 和 amount 变量。这是因为其通过捕获包含它的函数体内已经存在的 runningTotal 和 amount 变量而实现的。
由于没有修改 amount 变量,incrementor 实际上捕获并存储了该变量的一个副本,而该副本随着 incrementor 一同被存储。
然而,因为每次调用该函数的时候都会修改 runningTotal 的值,incrementor 捕获了当前 runningTotal 变量的引用,而不是仅仅复制该变量的初始值。捕获一个引用保证了当 makeIncrementor 结束时候并不会消失,也保证了当下一次执行 incrementor 函数时,runningTotal 可以继续增加。

6、闭包是引用类型

let alsoIncrementByTen = incrementByTen
alsoIncrementByTen()		// 40

7、结语

文章最后更新时间:2015年1月30日08:59:28。
欲了解更细致的请参考官方文档:Closures
友情提示:
信息收集于互联网,如果您发现错误或造成侵权,请及时通知本站更正或删除,具体联系方式见页面底部联系我们,谢谢。

其他相似内容:

热门推荐: