dopatraman
dopatraman

Reputation: 13908

Trouble understanding go function call syntax

I found this example here:

func(*myHandler) ServeHTTP(writer http.ResponseWriter, request *http.Request) {

    // What does this line do??
    if h, ok := route[request.URL.String()]; ok {
        h(writer, request)
        return
    }

    io.WriteString(writer, "my server: " + request.URL.String())
}

I am extremely puzzled by this line:

if h, ok := route[request.URL.String()]; ok { h(writer, request) }

first off, how can it be valid syntactically to declare ok after it is assigned to the result of route()?

second, if h is returned by route(), how can it be used in the definition of ok???

I am thoroughly confused by this. Gophers, please help.

Upvotes: 1

Views: 112

Answers (2)

janos
janos

Reputation: 124648

Take a look at this page in Tour of Go. It explains that:

Like for, the if statement can start with a short statement to execute before the condition.

Given your example:

h, ok := route[request.URL.String()]; ok { ... }

The short statement is h, ok := route[request.URL.String()]. The ; after marks the end of the short statement. The ok that follows is the condition. If true, then the code block {...} is executed. In that code block you can use all the variables that were assigned in the short statement.

first off, how can it be valid syntactically to declare ok after it is assigned to the result of route()?

ok is not declared after it is assigned. It is a boolean value, used in the condition.

second, if h is returned byroute(), how can it be used in the definition ofok`???

It's not definition of ok. It's the code block of the if statement.

Consider this alternative, almost equivalent writing style:

h, ok := route[request.URL.String()]
if ok {
    h(writer, request)
    return
}

This is perfectly clear, right? We just split the original code to two steps. But this is not the same. When writing this way, the h and ok variables are visible after the if statement. This is not desirable. It's a good practice to minimize the visibility of variables (also known as the live time). The longer a variable is visible, the longer the window of vulnerability during which it can be accidentally misused. This syntax of Go is truly great, genius, and I don't know a single other language where this kind of if statement is possible.

See also the section on the if statement in Effective Go.

Upvotes: 4

elithrar
elithrar

Reputation: 24250

Firstly: you should run through the Go Tour - specifically the section on Maps: https://tour.golang.org/moretypes/16

The "comma, ok" idiom here is designed to check that the key exists in the map. Doing a lookup on a non-existent key will panic (and likely crash your application).

if h, ok := route[request.URL.String()]; ok { h(writer, request) }

  • If request.URL.String() exists, set h and set ok to true.
  • If ok is true, then call the function h.
  • Otherwise, write the URL to the response (and do nothing further).

Upvotes: 3

Related Questions