How to implement a PHP function `die()` (or `exit()`) in Go?
Asked Answered
O

4

6

In PHP, die() is used to stop running the script for preventing the unexpected behaviour. In Go, what is the idiomatic way to die a handle function? panic() or return?

Overlive answered 27/7, 2016 at 6:24 Comment(0)
S
10

You should use os.Exit.

Exit causes the current program to exit with the given status code. Conventionally, code zero indicates success, non-zero an error. The program terminates immediately; deferred functions are not run.

package main

import (
    "fmt"
    "os"
)


func main() {
    fmt.Println("Start")
    os.Exit(1)
    fmt.Println("End")
}

Even, you can use panic, it's also stop normal execution but throw Error when execution stop.

The panic built-in function stops normal execution of the current goroutine. When a function F calls panic, normal execution of F stops immediately. Any functions whose execution was deferred by F are run in the usual way, and then F returns to its caller. To the caller G, the invocation of F then behaves like a call to panic, terminating G's execution and running any deferred functions. This continues until all functions in the executing goroutine have stopped, in reverse order. At that point, the program is terminated and the error condition is reported, including the value of the argument to panic. This termination sequence is called panicking and can be controlled by the built-in function recover.

package main

import "fmt"

func main() {
    fmt.Println("Start")
    panic("exit")
    fmt.Println("End")
}
Shauna answered 27/7, 2016 at 7:32 Comment(0)
M
3

If you don't want to print a stack trace after exiting the program, you can use os.Exit. Also you are able to set a specific exit code with os.Exit.

Example (https://play.golang.org/p/XhDkKMhtpm):

package main

import (
    "fmt"
    "os"
)

func foo() {
    fmt.Println("bim")
    os.Exit(1)
    fmt.Println("baz")
}

func main() {
    foo()
    foo()
}

Also be aware, that os.Exit immediately stops the program and doesn't run any deferred functions, while panic() does. See https://play.golang.org/p/KjGFZzTrJ7 and https://play.golang.org/p/Q4iciT35kP.

Mendez answered 27/7, 2016 at 7:3 Comment(0)
S
1

You can use panic in HTTP handler. Server will handle it. See Handler.

If ServeHTTP panics, the server (the caller of ServeHTTP) assumes that the effect of the panic was isolated to the active request. It recovers the panic, logs a stack trace to the server error log, and hangs up the connection.

Function panic is reserved for the situation when program just cannot continue. Inability to serve just one request is not the same as inability to continue to work, so I would log the error, set a correct HTTP status and use return. See Effective Go.

The usual way to report an error to a caller is to return an error as an extra return value. The canonical Read method is a well-known instance; it returns a byte count and an error. But what if the error is unrecoverable? Sometimes the program simply cannot continue.

Selfappointed answered 27/7, 2016 at 6:33 Comment(0)
L
1

The idiomatic way to break a function in Go is to use panic(). This is the defacto way to stop the execution of an event on runtime. If you want to recover the panic you can use the built in recover() function.

Panic explanation:

Panic is a built-in function that stops the ordinary flow of control and begins panicking. When the function F calls panic, execution of F stops, any deferred functions in F are executed normally, and then F returns to its caller.

https://blog.golang.org/defer-panic-and-recover

Recover explanation:

Recover is a built-in function that regains control of a panicking goroutine. Recover is only useful inside deferred functions. During normal execution, a call to recover will return nil and have no other effect. If the current goroutine is panicking, a call to recover will capture the value given to panic and resume normal execution.

https://blog.golang.org/defer-panic-and-recover

And here is a simple example:

package main

import "fmt"

func badCall() {
    panic("Bad call happend!")
}

func test() {
    defer func() {
        if err := recover(); err != nil {
            fmt.Printf("Panicking %s\n\r", err)
        }
    }()

    badCall()
    fmt.Println("This is never executed!!")
}

func main() {
    fmt.Println("Start testing")
    test()
    fmt.Println("End testing")
}
Linette answered 27/7, 2016 at 6:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.