The story I was addicted to when I specified nil as a function argument in Go

Preface

I think the story of go's nil is the nth decoction, but I will write an article to commemorate my addiction.

Since the actual code is a little longer and is in the framework, it was difficult to identify the cause, but I will write only the essence.

I made a method like this (failure example)

By the way, I intended to be a wrapper function because I throw HTTPRequest many times in the test code.

func Request(method, url string, body *strings.Reader) error {
	request, err := http.NewRequest(method, url, body)
	if err != nil {
		return err
	}
	request.Header.Set("Content-Type", "application/x-www-form-urlencoded")

	client := new(http.Client)
	resp, _ := client.Do(request)
	defer resp.Body.Close()
	byteArray, _ := ioutil.ReadAll(resp.Body)
	fmt.Println(string(byteArray))
	return nil
}

I'm assuming you'll use this method this way.

	
func main() {

	values := url.Values{
		"hoge": []string{"fuga"},
	}

	err := Request("POST", "https://google.com", strings.NewReader(values.Encode()))
	if err != nil {
		log.Fatal(err)
	}

}

For the 3rd argument of Request, ~~ Roughly ~~ I specified the return type of strings.NewReader as it is without thinking about anything.

Specify nil

Now, when there is nothing to send parameters in POST


	err := Request("POST", "https://google.com", nil)
	if err != nil {
		log.Fatal(err)
	}

I specify, but when I execute this

Crash with run-time error.

strings.(*Reader).Len(...)
        /usr/local/Cellar/go/1.15.3/libexec/src/strings/reader.go:26
net/http.NewRequestWithContext(0x1314620, 0xc00001a0b0, 0x12baeec, 0x3, 0x12be7e1, 0x12, 0x13102c0, 0x0, 0x121018d, 0x0, ...)
        /usr/local/Cellar/go/1.15.3/libexec/src/net/http/request.go:889 +0x2a4
net/http.NewRequest(...)
        /usr/local/Cellar/go/1.15.3/libexec/src/net/http/request.go:813
main.Request(0x12baeec, 0x3, 0x12be7e1, 0x12, 0x0, 0x0, 0x0)

By the way, it's okay if you specify nil directly in the third argument of http.NewRequest.

	req, err := http.NewRequest("POST", "https://google.com", nil)
	if err != nil {
		log.Fatal(err)
	}

What is the reason for the error?

As you can see by stepping through IntelliJ IDEA,

https://github.com/golang/go/blob/f2eea4c1dc37886939c010daff89c03d5a3825be/src/net/http/request.go#L887

if body != nil {

Go's nil is a typed semantics, so it goes inside the function with the type of * strings.NewReader, even though the body itself is nil in the code below. Since the type of the body content itself is * strings.NewReader and the body declaration is io.Reader The nil judgment is true (unintentionally?), And it means that it is in the if and an error occurs.

reference: https://qiita.com/umisama/items/e215d49138e949d7f805

If nil is specified in the function argument, it becomes the argument type of the function declaration.

req, err := http.NewRequest("POST", "https://google.com", nil)

Well, the nil specified here, but from the definition of NewRequest It becomes nil of io.Reader. (io.Reader is also typed in interface)

What should i do

func Request(method, url string, body *strings.Reader) Arguments of func Request(method, url string, body io.Reader)

It should have been, so even though it is a disposable function in the test, It was safe to match the function argument to the type of the function used inside, not the type of the caller.

Conclusion

When nil is specified in the 3rd argument of http.NewRequest, specify it to be the type of io.Reader.

Declare function arguments as close to the type called inside as possible.

It is often said that nil is addicted to it, but I thought that I wouldn't notice it unless I was actually addicted to it.

Recommended Posts

The story I was addicted to when I specified nil as a function argument in Go
A story I was addicted to when inserting from Python to a PostgreSQL table
What I was addicted to when creating a web application in a windows environment
[Fabric] I was addicted to using boolean as an argument, so make a note of the countermeasures.
A story that I was addicted to at np.where
A story that I was addicted to when I made SFTP communication with python
When I tried to install PIL and matplotlib in a virtualenv environment, I was addicted to it.
The record I was addicted to when putting MeCab on Heroku
A note I was addicted to when making a beep on Linux
A note I was addicted to when creating a table with SQLAlchemy
Create a function to get the contents of the database in Go
When I tried to scrape using requests in python, I was addicted to SSLError, so a workaround memo
A story that didn't work when I tried to log in with the Python requests module
A story I was addicted to trying to install LightFM on Amazon Linux
A story I was addicted to trying to get a video url with tweepy
The file name was bad in Python and I was addicted to import
Function to extract the maximum and minimum values ​​in a slice with Go
[Python] I want to know the variables in the function when an error occurs!
[Python] I tried to get the type name as a string from the type function
A note I was addicted to when running Python with Visual Studio Code
[Words spelled to me when I was in the first grade ①] I'm not afraid to build a programming environment.
In IPython, when I tried to see the value, it was a generator, so I came up with it when I was frustrated.
I was addicted to scraping with Selenium (+ Python) in 2020
A simple difference when passing a pointer as a function argument
I was addicted to trying logging.getLogger in Flask 1.1.x
What I was addicted to when using Python tornado
I was soberly addicted to calling awscli from a Python 2.7 script registered in crontab
A story that was convenient when I tried using the python ip address module
Note that I was addicted to npm script not passing in the verification environment
What I was addicted to when combining class inheritance and Joint Table Inheritance in SQLAlchemy
What I did when I was angry to put it in with the enable-shared option
When a local variable with the same name as a global variable is defined in the function
As for the process type written in honcho's Procfile, I was addicted to it for over an hour because I couldn't use-, so I'll write it as a show.
[Small story] A painstaking measure when you have to execute a function before import in Python
A word that I was interested in as a programming beginner
A story that went missing when I specified a path starting with a tilde (~) in python open
What I was addicted to when migrating Processing users to Python
I wrote it in Go to understand the SOLID principle
To write a test in Go, first design the interface
I tried to implement the mail sending function in Python
The story of when I was addicted to Caused by SSLError ("Can't connect to HTTPS URL because the SSL module is not available.")
I wrote AWS Lambda, and I was a little addicted to the default value of Python arguments
Note that I was addicted to accessing the DB with Python's mysql.connector using a web application.
When I try to divide a list with MeCab, I get'TypeError: in method'Tagger_parse', argument 2 of type'char const *''
When I put Django in my home directory, I was addicted to static files with permission errors
[Linux] I want to know the date when the user logged in
Precautions when using a list or dictionary as the default argument
What I was addicted to when introducing ALE to Vim for Python
What I was addicted to with json.dumps in Python base64 encoding
I wrote a function to load a Git extension script in Python
Utilization of lambda (when passing a function as an argument of another function)
The story that the guard was confined when the laboratory was converted to IoT
I was addicted to confusing class variables and instance variables in Python
I made a command to display a colorful calendar in the terminal
Attempt to extend a function in the library (add copy function to pathlib)
A story addicted to Azure Pipelines
I was addicted to multiprocessing + psycopg2
I want to save the trouble of inputting when debugging Paiza's skill check example in a local environment such as Jupyter [Python]
[Python] When I tried to make a decompression tool with a zip file I just knew, I was addicted to sys.exit ()
The story of creating a store search BOT (AI LINE BOT) for Go To EAT in Chiba Prefecture (1)
I want to load the pytest fixture as a library somewhere else (pytest may not exist in the environment)