Swift from Scratch: Closures

如果你和c/oc中的block或者ruby中的lambda打过交道,那么你对于接受closure的概念不会有多大问题。closures就是打包过的代码,你可以在你的代码中传递。
事实上,我们在之前的两篇文章中已经使用过closures。函数也是closures。让我们开始讨论closure。

What Is a Closure?

正如我所说的,closure是打包过的代码,你可以在你的代码间进行传递。你可以将closure作为函数的实参用,你也可以将其作为某个对象的性质。closures有许多使用案例。
closure暗示了closures的一个关键特征。closure抓住了在其定义环境中的变量和常量。

Flexibility

你已经看到函数是多么的强大和灵活。因为函数是closures,closures也非常灵活。在这篇文章中,你会发现closure是多么灵活和强大。

Memory Management

c编程语言有一个相同的概念,blocks。swift中的closures有一些好处,closures在swift中的一个关键优势是,你作为开发者,不需要考虑存储管理。

Syntax

closure的语法不是很困难,这会让你回忆起全局和嵌套函数。看看下面的例子

{(a:Int)->Int in 
    return a+1
}

你首先注意的是整个closure被包裹在大括号中。closure的参数被包括在括号中,通过->符号与返回类型分开。上面的closure接受一个实参,a,类型是Int,返回Int。closure的体从in关键字开始。
命名的closure,即全局函数和嵌套函数,看起来略有不同。下面的例子阐明了这个不同

func increment(a:Int)->Int{
    return a+1
}

主要的不同是func关键字的使用,还有参数和返回类型的位置。closure以大括号开始,以大括号结尾,包裹了参数,返回类型和closure主体,除了这些不同,记住每个函数就是一个closure。但是不是每个closure都是函数。

Closures as Parameters

closures非常强大,下面的例子阐明了它们是多么的有用。

var status=["California","New York","Texas","Alska"]
let abbreviatedStates=states.map({(state:String)->String in return state.substringToIndex(advance(state.startIndex,2)).uppercaseString})
println(abbreviatedStates)

map函数或者方法在许多编程语言和库中很常见,例如PHP,Ruby,jQuery。在上面的例子中,states数组调用了map函数,改变了它的内容。返回了一个新的数组。

Type Inference

在这个系列的前面,我们知道Swift非常聪明。让我们再看看到底有多聪明。这个states数组是字符串数组。因为我们在数组中调用了map函数,swift知道state是String类型。这意味着我们可以省略类型。看看下面更新后的版本

let abbreviations=states.map({(state)->String in
    return state.substringToIndex(advance(state.startIndex,2)).uppercase
})

在上面的例子中我们可以省略更多

let abbreviations=states.map({state in state.substringToIndex(advance(state.startIndex,2)).uppercase})

让我解释到底发生了什么,编译器能够推断我们传递到map函数的closure返回一个string,这意味着我们不需要在closure定义中包括返回类型。我们能这样写只有在closure body只有一个语句的前提下。在这种情况下,我们可以将该语句放在closure定义的同一行。因为定义中没有返回类型也没有->符号在返回类型之前。我们可以省略closures参数的括号。

Shorthand Argument Names

到此还没有结束,我们可以利用Shorthand Argument Names进一步的精简上面closure的表达。当我们使用内嵌closure表达式时,我们可以省略参数名单,包括分隔参数和closure body的in关键字。
在closure body 中,我们用shorthand argument names引用实参。Swift提供了我们 0 1。
下面的这个更新后的例子,我省略了参数列表和in关键字。将state实参用$0来代替。

let abbreivations=states.map({$0.substringToIndex(advance($0.startIndex,2)).uppercase})

Trailing Closures

Swift编程语言也定义了trailing closures的概念。这个点子很简单,如果你将closure作为函数的最后一个实参,你可以将closure放在函数调用括号的外面。下面的例子演示了这是如何工作的

let abbreviations=states.map(){{$0.substringToIndex(advance($0.startIndex,2)).uppercase}}

如果函数的实参只有一个closure,可以将括号也去掉。

let abbreviations = states.map { $0.substringToIndex(advance($0.startIndex, 2)).uppercaseString }

注意这在closure中包含多个语句的情形下也适用。事实上,这是trailing closures在Swift中能用的主要原因。如果一个closure很长且复杂,而且是函数的最后一个实参,通常使用trailing closure的语法会更好。

let abbreviations = states.map { (state: String) -> String in
    let newState = state.substringToIndex(advance(state.startIndex, 2))
    return newState.uppercaseString
}

Capturing Values

当你使用closures,你会发现你经常使用或者操作closures定义环境中的常量和变量在closures的body中。这是可能的,被称为value capturing意思就是closure可以抓取它被定义时候的环境中的常量和变量的值。看看下面的例子来更好的理解value capturing的概念

func changeCase(uppercase:Bool,strings:String...)->[String]
{
    var newStrings=[String]()
    func changeToUppercase(){
        for s in strings{
            newStrings.append(s.uppercaseString)
        }
    }
    func changeToLowercase(){
        for s in strings{
            newStrings.append(s.lowercaseString)
        }
    }
    if uppercase{
        changeToUppercase()
    }
    else{
        changeToLowercase()
    }
    return newStrings
}

let uppercaseStates=changeCase(true, "Califorina","New York")
let lowercaseStates=changeCase(false, "Califorina","New York")

我确定你会觉得上面的例子有点做作,但是它显示了Swift中value capturing是如何起作用的。嵌套函数,changeToUppercase和changeToLowercase,可以访问外面函数的实参,states和newStates。让我解释下发生了什么。
changeCase函数接受了一个布尔值作为第一个实参和一个variadic参数类型为String作为第二个参数。这个函数返回一个类型为string的数组。在函数体中,我们生成了一个可变的数组,newStrings,作为存储处理过后的string。
嵌套函数对传递到changeCase函数的字符串进行循环,然后改变每个字符串。正如你看到的,这些嵌套函数可以访问传递到changeCase函数的字符串,同样可以访问newStrings数组,这个数组声明在changeCase函数体中。
我们检查uppercase的值,调用正确的函数,返回newStrings数组。最后两行演示了如何使用changeCase函数。

Closures

这篇文章中提到了数次,函数是closures。closures可以分为三种

  • 全局函数
  • 嵌套函数
  • closure表达式
    全局函数,类似swift标准库的println函数。嵌套函数,可以捕获它们外层函数的常量和变量。
    closure表达式,也被称为未命名closure,可以捕获它们定义时所在环境的变量和常量的值。这和嵌套函数很相似。

Copying and Referencing

一个捕获变量值的closure有能力改变这个变量的值。swift足够聪明知道它应该复制或者引用常量和变量的值。

Conclusion

closure是一个非常重要的概念。它允许你写灵活的动态的代码,易于理解。在下面的系列中,我们会探索swift中面向对象编程,以对象,结构和类开始。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值