Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

226
Vistas
How exactly are structs captured in escaping closures?

It seems logical to me that escaping closures would capture structs by copying. But if that was the case, the following code makes no sense and should not compile:

struct Wtf {
    var x = 1
}

func foo(){
    
    var wtf = Wtf()
    
    DispatchQueue.global().async {
        wtf.x = 5
    }
    
    Thread.sleep(forTimeInterval: 2)
    print("x = \(wtf.x)")
}

Yet it compiles successfully and even prints 5 when foo is called. How is this possible?

over 4 years ago · Santiago Trujillo
1 Respuestas
Responde la pregunta

0

While it might make sense for a struct to be copied, as your code demonstrates, it is not. That's a powerful tool. For example:

func makeCounter() -> () -> Int {
    var n = 0
    return {
        n += 1  // This `n` is the same `n` from the outer scope
        return n
    }

    // At this point, the scope is gone, but the `n` lives on in the closure.
}

let counter1 = makeCounter()
let counter2 = makeCounter()

print("Counter1: ", counter1(), counter1())  // Counter1:  1 2
print("Counter2: ", counter2(), counter2())  // Counter2:  1 2
print("Counter1: ", counter1(), counter1())  // Counter1:  3 4

If n were copied into the closure, this couldn't work. The whole point is the closure captures and can modify state outside itself. This is what separates a closure (which "closes over" the scope where it was created) and an anonymous function (which does not).

(The history of the term "close over" is kind of obscure. It refers to the idea that the lambda expression's free variables have been "closed," but IMO "bound" would be a much more obvious term, and is how we describe this everywhere else. But the term "closure" has been used for decades, so here we are.)

Note that it is possible to get copy semantics. You just have to ask for it:

func foo(){

    var wtf = Wtf()

    DispatchQueue.global().async { [wtf] in // Make a local `let` copy
        var wtf = wtf   // To modify it, we need to make a `var` copy
        wtf.x = 5
    }

    Thread.sleep(forTimeInterval: 2)
    // Prints 1 as you expected
    print("x = \(wtf.x)")
}

In C++, lambdas have to be explicit about how to capture values, by binding or by copying. But in Swift, they chose to make binding the default.

As to why you're allowed to access wtf after it's been captured by the closure, that's just a lack of move semantics in Swift. There's no way in Swift today to express "this variable has been passed to something else and may no longer be accessed in this scope." That's a known limitation of the language, and a lot of work is going into fix it. See The Ownership Manifesto for more.

over 4 years ago · Santiago Trujillo Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda