如何在Swift中创建局部范围?

时间:2014-06-03 09:13:24

标签: swift

我经常使用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中创建局部范围?

5 个答案:

答案 0 :(得分:72)

更新:在Swift 2.0中,您只需使用do关键字:

do {
    let label = UILabel()
    self.addSubview(label)
    self.titleLabel = label
}

对于Swift pre-2.0来说这是真的:

您可以定义与此类似的内容:

func locally(@noescape work: () -> ()) {
    work()
}

然后使用如下的locally块:

locally {
    let g = 42
    println(g)
}

(灵感来自Scala的 Predef 对象中的locally。)

答案 1 :(得分:6)

我认为不可能。

iBooks商店中至少有一本书中的语法没有提到它。

你可以这样做,

if (true) {
    let a = 4
}

但我认为,这是一种不好的做法。

答案 2 :(得分:3)

Swift 2 开始,您可以使用do语句创建一个本地范围:

do {
    let x = 7
    print(x)
}
print(x) // error: use of unresolved identifier 'x'

然而,主要的用例似乎是使用do-try-catch进行错误处理, 如"Error Handling"中所述 在"The Swift Programming Language"中,例如:

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)")
}

答案 3 :(得分:2)

如评论中所述,C中的匿名嵌套作用域通常表示您可以编写更好的代码。例如,您可以使用最终设置self.titleLabel的嵌套范围中的工作,而不是简单地工作 您可以改为将该赋值作为评估内联闭包的结果:

self.titleLabel = {
    let label = UILabel()
    label.text = "some text"
    // ... set other properties ...
    self.addSubview(label)
    return label
}()

这不仅将label保留为一个很好的短名称,它只限于创建和配置一个代码块的代码块,但保留了与为其创建值的属性相关联的代码块。 它更模块化,因为你可以用一些其他标签创建函数来替换整个闭包,如果它有用来分解代码。

如果您发现自己经常这样做,可以尝试制作一个通用函数,让您将构造代码剪切到此:

self.titleLabel = makeSubview(UILabel()) { label in
    label.text = "some text"
    // other label properties
}

但我会把这样的功能定义为读者的练习。 ;)


正如Jean-Philippe Pellet's answer中所述,在Swift 2.0及更高版本中,do构造是显式语言提供的方法。 (对于仍在使用Swift 1.x的人来说,他建议的基于功能的解决方案是一个不错的选择。)

另一个Swift 1.x解决方案 - 没有定义新函数 - 是(显式地)抛弃立即执行的闭包的结果:

 _ = {
     print("foo")
 }() 

答案 4 :(得分:-1)

我所做的是定义一个匿名函数并执行它。

// ... 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 {...}。正如Martin指出的那样,在Swift 2中,do {...}将被允许作为定义任意范围的官方方式,从而很好地解决了这个问题。