How to create local scopes in Swift?
Solution 1:
Update: In Swift 2.0, you just use the do
keyword:
do {
let label = UILabel()
self.addSubview(label)
self.titleLabel = label
}
This was true for Swift pre-2.0:
You can define something similar to this:
func locally(@noescape work: () -> ()) {
work()
}
And then use such a locally
block as follows:
locally {
let g = 42
println(g)
}
(Inspired by locally
in Scala's Predef object.)
Solution 2:
As of Swift 2, you can create a local scope with the do
-statement:
do {
let x = 7
print(x)
}
print(x) // error: use of unresolved identifier 'x'
The main use-case however seems to be error-handling with do-try-catch, as documented in "Error Handling" in "The Swift Programming Language", for example:
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)")
}
Solution 3:
I don't think it is possible.
At least a grammar that is in the book that is available in iBooks store does not mention it.
You could do this,
if (true) {
let a = 4
}
but I think, it is a bad practice.
Solution 4:
As noted in comments, anonymous nested scopes in C are often a sign that you could be writing better code. For example, instead of simply doing work in a nested scope that ultimately sets self.titleLabel
, you could
you could instead make that assignment the result of evaluating an inline closure:
self.titleLabel = {
let label = UILabel()
label.text = "some text"
// ... set other properties ...
self.addSubview(label)
return label
}()
This not only keeps label
as a nice short name that's scoped only to the chunk of code that creates and configures one, but keeps that chunk of code associated with the property it's creating a value for. And it's more modular, in that you could replace the whole closure with a call to some other label-creating function should it ever become useful to factor out that code.
If you find yourself doing this sort of thing frequently, you could try making a generic function that lets you cut your construction code down to this:
self.titleLabel = makeSubview(UILabel()) { label in
label.text = "some text"
// other label properties
}
But I'll leave defining such a function as an exercise for the reader. ;)
As noted in Jean-Philippe Pellet's answer, in Swift 2.0 and later the do
construct is the explicitly language-provided way to do this. (And the function-based solution he suggests is a decent option for anyone still using Swift 1.x.)
Another Swift 1.x solution — without defining a new function — is to (explicitly) throw away the result of an immediately-executed closure:
_ = {
print("foo")
}()