the - ¿Cómo crear ámbitos locales en Swift?
swift(lenguaje de programación) (5)
A partir de Swift 2 , puede crear un ámbito local con la declaración de do
:
do {
let x = 7
print(x)
}
print(x) // error: use of unresolved identifier ''x''
Sin embargo, el principal caso de uso parece ser el manejo de errores con do-try-catch, como se documenta en "Manejo de errores" en "The Swift Programming Language" , por ejemplo:
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)")
}
Regularmente estoy usando los ámbitos locales en Objective-C para que los nombres sean más claros.
{
UILabel *label = [[UILabel alloc] init];
[self addSubview:label];
self.titleLabel = label;
}
Estoy intentando reescribir este código en Swift así:
{
let label = UILabel()
self.addSubview(label)
self.titleLabel = label
}
Esto me da el siguiente error:
Error: Braced block of statements is an unused closure.
Entonces, ¿cómo puedo crear un ámbito local en Swift?
Como se señaló en los comentarios, los ámbitos anónimos anidados en C son a menudo una señal de que podría estar escribiendo un código mejor. Por ejemplo, en lugar de simplemente trabajar en un ámbito anidado que en última instancia establece self.titleLabel
, podría hacer que esa asignación sea el resultado de evaluar un cierre en línea:
self.titleLabel = {
let label = UILabel()
label.text = "some text"
// ... set other properties ...
self.addSubview(label)
return label
}()
Esto no solo mantiene a la label
como un nombre corto agradable que se encuentra dentro del ámbito del código que crea y configura uno, sino que mantiene ese fragmento de código asociado con la propiedad para la que está creando un valor. Y es más modular, ya que podría reemplazar todo el cierre con una llamada a alguna otra función de creación de etiquetas en caso de que alguna vez sea útil para factorizar ese código.
Si te encuentras haciendo este tipo de cosas con frecuencia, puedes intentar crear una función genérica que te permita reducir tu código de construcción a esto:
self.titleLabel = makeSubview(UILabel()) { label in
label.text = "some text"
// other label properties
}
Pero dejaré de definir esa función como un ejercicio para el lector. ;)
Como se señaló en la respuesta de Jean-Philippe Pellet , en Swift 2.0 y más adelante, la construcción do
es la forma explícita en el idioma de hacerlo. (Y la solución basada en la función que sugiere es una opción decente para cualquier persona que todavía use Swift 1.x.)
Otra solución Swift 1.x, sin definir una nueva función, es deshacerse (explícitamente) del resultado de un cierre ejecutado de inmediato:
_ = {
print("foo")
}()
Lo que hago es definir una función anónima y ejecutarla.
// ... preceding code ...
// ... might need semicolon here;
{
() -> () in
// ... this is a local scope ...
}()
// ... following code ...
Es posible que tenga que poner un punto y coma al final de la línea anterior para que Swift no piense que esto es un "cierre final". Incluso puede colocar ese punto y coma en la misma línea justo antes de la apertura de la abrazadera. Entonces, implementando el código original del OP:
;{
() -> () in
let label = UILabel()
self.addSubview(label)
self.titleLabel = label
}()
EDITAR Posteriormente me he encontrado recurriendo a if true {...}
lugar. Sin embargo, como señala Martin, en Swift 2, se permitirá do {...}
como la forma oficial de definir un alcance arbitrario, resolviendo así el problema.
No creo que sea posible.
Al menos una gramática que está en el libro que está disponible en la tienda iBooks no lo menciona.
Podrías hacer esto,
if (true) {
let a = 4
}
Pero creo que es una mala práctica.
Actualización: En Swift 2.0, solo usa la palabra clave do
:
do {
let label = UILabel()
self.addSubview(label)
self.titleLabel = label
}
Esto fue cierto para Swift pre-2.0:
Puedes definir algo similar a esto:
func locally(@noescape work: () -> ()) {
work()
}
Y luego use un bloque locally
siguiente manera:
locally {
let g = 42
println(g)
}
(Inspirado locally
en el objeto Predef de Scala).