如何在Swift中创build局部范围?
我经常在Objective-C中使用本地范围来使命名更清晰。
{ UILabel *label = [[UILabel alloc] init]; [self addSubview:label]; self.titleLabel = label; }
我试图在Swift中重写这样的代码:
{ let label = UILabel() self.addSubview(label) self.titleLabel = label }
这让我得到以下错误:
Error: Braced block of statements is an unused closure.
那么如何在Swift中创build一个本地作用域?
更新:在Swift 2.0中,您只需使用do
关键字:
do { let label = UILabel() self.addSubview(label) self.titleLabel = label }
Swift 2.0之前的版本是这样的:
你可以定义类似这样的东西:
func locally(@noescape work: () -> ()) { work() }
然后使用这样的本地块如下:
locally { let g = 42 println(g) }
(受Scala的Predef对象的locally
启发。)
我不认为这是可能的。
至less在iBooks商店中可用的书中的语法没有提及它。
你可以做到这一点,
if (true) { let a = 4 }
但我认为,这是一个不好的做法。
从Swift 2开始 ,可以使用do
-statement创build一个本地范围:
do { let x = 7 print(x) } print(x) // error: use of unresolved identifier 'x'
但是,主要用例似乎是do-try-catch的error handling ,如“Swift编程语言”中的“error handling”中所述,例如:
do { let jsonObj = try NSJSONSerialization.JSONObjectWithData(jsonData, options: []) // success, do something with `jsonObj`... } catch let error as NSError { // failure print("Invalid JSON data: \(error.localizedDescription)") }
正如评论中指出的那样,C语言中的匿名嵌套作用域通常表示您可以编写更好的代码。 例如,不是简单地在最终设置self.titleLabel
的嵌套作用域中进行工作,而是可以将该作业作为评估内联closures的结果:
self.titleLabel = { let label = UILabel() label.text = "some text" // ... set other properties ... self.addSubview(label) return label }()
这不仅将label
保持为一个很好的简短名称,它仅限于创build和configuration一个代码块的代码块,而是保持与创build它的值的属性相关联的代码块。 而且它更加模块化,因为你可以用一个其他标签创build函数来replace整个闭包,如果它有用于分解代码。
如果你经常发现自己在做这样的事情,你可以尝试制作一个通用的函数,让你把你的构造代码降低到这个:
self.titleLabel = makeSubview(UILabel()) { label in label.text = "some text" // other label properties }
但是我会留下这样一个function来作为读者的练习。 ;)
正如Jean-Philippe Pellet的回答中所指出的那样,在Swift 2.0和之后的版本中, do
构造是明确的语言提供的方式。 (他build议基于function的解决scheme对于仍在使用Swift 1.x的人来说是一个不错的select)
另一个Swift 1.x解决scheme – 没有定义一个新的函数 – 是(明确地)抛弃立即执行的闭包的结果:
_ = { print("foo") }()
我所做的是定义一个匿名函数并执行它。
// ... preceding code ... // ... might need semicolon here; { () -> () in // ... this is a local scope ... }() // ... following code ...
你可能需要在上一行的末尾加上分号,所以Swift不认为这是一个“尾随结束”。 您甚至可以在打开大括号之前将该分号放在同一行中。 所以,实现OP的原始代码:
;{ () -> () in let label = UILabel() self.addSubview(label) self.titleLabel = label }()
编辑随后,我发现自己堕落, if true {...}
而不是。 正如马丁指出的那样,尽pipe在Swift 2中, do {...}
将被允许作为定义任意范围的官方方式,从而很好地解决了这个问题。