Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is http.Client{} prefixed with &?

I am learning Go and I am reading Go's official documentation about net/http, and I write following code from doc for test:

package main

import (
    "net/http"
    "fmt"
)

func main() {
    client := &http.Client{}
    resp, _ := client.Get("http://example.com")

    fmt.Println(resp)
}

http.Client is a struct, but I do not know why there is a & pointer prefixed. I think creating a http.Client reference is not necessary. And why does the client variable have a Get method? I am reading the source code of net/http, it defines the Client struct below:

type Client struct {
    Transport RoundTripper
    CheckRedirect func(req *Request, via []*Request) error
    Jar CookieJar
    Timeout time.Duration
}

The Client struct does not have a Get method defined; why does the client variable have a Get method?

like image 528
TangMonk Avatar asked Aug 18 '17 08:08

TangMonk


People also ask

What is go HTTP client?

Go is a language designed by Google for use in a modern internet environment. It comes with a highly capable standard library and a built-in HTTP client.

What is HTTP transport Golang?

It establishes network connections as needed 40 // and caches them for reuse by subsequent calls. It uses HTTP proxies 41 // as directed by the $HTTP_PROXY and $NO_PROXY (or $http_proxy and 42 // $no_proxy) environment variables.


Video Answer


1 Answers

I would really take the Go Tour to get a feeling of the language and its basic syntax first.

The type declaration you quoted only contains the fields of the struct, but not its methods. Methods are defined elsewhere, like functions but with a receiver added which designates the type they belong to. For example the definition of Client.Get() method is this:

func (c *Client) Get(url string) (resp *Response, err error) {
    req, err := NewRequest("GET", url, nil)
    if err != nil {
        return nil, err
    }
    return c.Do(req)
}

The part before the method name is called the receiver, and that designates the type the method belogns to (*Client in this example). See Spec: Method declarations for more details.

The & is an address operator, it takes the address of its operand. In this case the local variable client will be of type *http.Client. http.Client{} is a composite literal which creates a value of the struct type http.Client, and & takes the address of the anonymous variable where this struct value is stored:

Taking the address of a composite literal generates a pointer to a unique variable initialized with the literal's value.

It is used so that the client variable will be a pointer to an http.Client value, one that is encouraged to be shared and reused:

The Client's Transport typically has internal state (cached TCP connections), so Clients should be reused instead of created as needed. Clients are safe for concurrent use by multiple goroutines.

And if client is a pointer, you are free to pass it around to other functions, only the pointer value will be copied, not the pointed http.Client struct, so the struct itself (the http.Client value) will be reused. Should you not use a pointer, if you would pass it to other functions, the struct itself would be copied and not reused.

Note that in this simple example it doesn't really matter, as even though all methods of http.Client are declared with pointer receiver, you can still call pointer methods on non-pointer variables, as client.Get() would be a shorthand for (&client).Get(). This is mentioned in Spec: Calls:

If x is addressable and &x's method set contains m, x.m() is shorthand for (&x).m().

So even though the & address operator is not needed in this simple example, it's good to keep the habit of using it, should the example grow or should you write code where this does matter (e.g. you pass around the created client).

like image 152
icza Avatar answered Nov 12 '22 03:11

icza