This is the 15th day of my participation in the Gwen Challenge.More article challenges

Code encapsulation can be a chore, but sometimes encapsulation can cause problems. This article documented a problem with nil determination that individuals encountered when encapsulating HTTP requests.

What is nil

Nil A built-in variable that represents null values, and only Pointers, channels, methods, interfaces, maps, and slices can be assigned nil.

Buildin/buildin. Go:

// nil is a predeclared identifier representing the zero value for a
// pointer, channel, func, interface, map, or slice type.
var nil Type // Type must be a pointer, channel, func, interface, map, or slice type

// Type is here for the purposes of documentation only. It is a stand-in
// for any Go type, but represents the same type for any given function
// invocation.
type Type int
Copy the code

The problem code

The following code is my wrapper around the HTTP. Post method

func (r *Request) Post(endpoint string, params *url.Values, body io.Reader, headers map[string]string, cookies map[string]string) (resp *http.Response, err error) {
    url := fmt.Sprintf("%s%s", r.BaseURL, endpoint)
    var req *http.Request
    req, err = http.NewRequest(http.MethodPost, url, body)
    iferr ! =nil {
        return
    }
    r.setRequest(req, params, headers, cookies)
    resp, err = r.Client.Do(req)
    return
}
Copy the code

Then use it like this:

var body *bytes.Reader
body = nil

resp, err = req.Post(endpoint, nil, body, nil.nil)
Copy the code

NewRequest (http.newRequest, http.newRequest, http.newRequest, http.newRequest)

Error analysis

The underlying implementation of Pointers and interfaces has two parts: Data and Type. When Pointers and interfaces are explicitly assigned nil, both data and type are nil, but when a value of type not nil but data is nil is assigned to a pointer or interface, the comparison to nil results in false.

Modify the code

Use reflect.valueof (body).isnil () to determine if the body is empty:

func (r *Request) Post(endpoint string, params *url.Values, body io.Reader, headers map[string]string, cookies map[string]string) (resp *http.Response, err error) {
    url := fmt.Sprintf("%s%s", r.BaseURL, endpoint)
    var req *http.Request
    if reflect.ValueOf(body).IsNil() {
        req, err = http.NewRequest(http.MethodPost, url, nil)}else {
        req, err = http.NewRequest(http.MethodPost, url, body)
    }
    iferr ! =nil {
        return
    }
    r.setRequest(req, params, headers, cookies)
    resp, err = r.Client.Do(req)
    return
}
Copy the code