Buscar..


Introducción

Una declaración defer empuja una llamada de función a una lista. La lista de llamadas guardadas se ejecuta después de que vuelve la función que la rodea. El aplazamiento se usa comúnmente para simplificar las funciones que realizan varias acciones de limpieza.

Sintaxis

  • diferir someFunc (args)
  • aplazar func () {// el código va aquí} ()

Observaciones

La función de defer inyecta un nuevo marco de pila (la función llamada después de la palabra clave de defer ) en la pila de llamadas debajo de la función que se está ejecutando actualmente. Esto significa que se garantiza que el aplazamiento se ejecute siempre que la pila se desenrolle (si su programa falla o obtiene un SIGKILL , el aplazamiento no se ejecutará).

Diferir lo básico

Una declaración diferida en Go es simplemente una llamada de función marcada para ejecutarse en un momento posterior. La declaración diferida es una llamada de función ordinaria prefijada por la palabra clave defer .

defer someFunction()

Una función diferida se ejecuta una vez la función que contiene los defer retorne el comando. La llamada real a la función diferida se produce cuando la función de cierre:

  • ejecuta una declaración de retorno
  • se cae del final
  • pánico

Ejemplo:

func main() {
    fmt.Println("First main statement")
    defer logExit("main") // position of defer statement here does not matter
    fmt.Println("Last main statement")
}

func logExit(name string) {
    fmt.Printf("Function %s returned\n", name)
}

Salida:

First main statement
Last main statement
Function main returned

Si una función tiene varias declaraciones diferidas, forman una pila. El último defer es el primero que se ejecuta después de que se devuelve la función de cierre, seguido de las llamadas subsiguientes a los defer anteriores en orden (a continuación, el ejemplo devuelve causando un pánico):

func main() {
    defer logNum(1)
    fmt.Println("First main statement")
    defer logNum(2)
    defer logNum(3)
    panic("panic occurred")
    fmt.Println("Last main statement") // not printed
    defer logNum(3) // not deferred since execution flow never reaches this line
}

func logNum(i int) {
    fmt.Printf("Num %d\n", i)
}

Salida:

First main statement
Num 3
Num 2
Num 1
panic: panic occurred

goroutine 1 [running]:
....

Tenga en cuenta que las funciones diferidos han evaluado sus argumentos en el momento defer ejecuta:

func main() {
    i := 1
    defer logNum(i) // deferred function call: logNum(1)
    fmt.Println("First main statement")
    i++
    defer logNum(i) // deferred function call: logNum(2)
    defer logNum(i*i) // deferred function call: logNum(4)
    return // explicit return
}

func logNum(i int) {
    fmt.Printf("Num %d\n", i)
}

Salida:

First main statement
Num 4
Num 2
Num 1

Si una función ha nombrado valores de retorno, una función anónima diferida dentro de esa función puede acceder y actualizar el valor devuelto incluso después de que la función haya regresado:

func main() {
    fmt.Println(plusOne(1)) // 2
    return
}

func plusOne(i int) (result int) { // overkill! only for demonstration
    defer func() {result += 1}() // anonymous function must be called by adding ()

    // i is returned as result, which is updated by deferred function above
    // after execution of below return
    return i
}

Finalmente, una sentencia de defer generalmente se usa en operaciones que a menudo ocurren juntas Por ejemplo:

  • abrir y cerrar un archivo
  • conectar y desconectar
  • bloquear y desbloquear un mutex
  • marcar un grupo de espera como hecho ( defer wg.Done() )

Este uso garantiza la liberación adecuada de los recursos del sistema independientemente del flujo de ejecución.

resp, err := http.Get(url)
if err != nil {
return err
}
defer resp.Body.Close() // Body will always get closed

Llamadas de función diferida

Las llamadas a funciones diferidas tienen un propósito similar a cosas como los bloques finally en lenguajes como Java: aseguran que alguna función se ejecutará cuando se devuelva la función externa, independientemente de si se produjo un error o qué declaración de devolución se golpeó en casos con múltiples devoluciones. Esto es útil para limpiar recursos que deben cerrarse como conexiones de red o punteros de archivos. La palabra clave defer indica una llamada a función diferida, de manera similar a la palabra clave go inicia una nueva goroutina. Al igual que una llamada go , los argumentos de la función se evalúan inmediatamente, pero a diferencia de la llamada go , las funciones diferidas no se ejecutan simultáneamente.

func MyFunc() {
    conn := GetConnection()    // Some kind of connection that must be closed.
    defer conn.Close()        // Will be executed when MyFunc returns, regardless of how.
    // Do some things...
    if someCondition {
        return                // conn.Close() will be called
    }
    // Do more things
}// Implicit return - conn.Close() will still be called

Tenga en cuenta el uso de conn.Close() lugar de conn.Close : no solo está pasando una función, está aplazando una llamada de función completa, incluidos sus argumentos. Las múltiples llamadas de función se pueden diferir en la misma función externa, y cada una se ejecutará una vez en orden inverso. También puede aplazar los cierres, ¡no se olvide de los parens!

defer func(){
    // Do some cleanup
}()


Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow