Golang函数或方法传递nil值的一个坑
package t13_niu_error
import (
"bytes"
"fmt"
"io/ioutil"
"net/http"
"testing"
)
// 将请求获取的数据转为string,支持GET或POST请求
func BaseRequestString(requestMethod, url string, requestBody *bytes.Reader) (string, error) {
client := &http.Client{
}
var req *http.Request
var err error
// 特别注意这里,即使外边requestBody传nil的话
// 但是它的类型type是 *bytes.Reader,传给http.NewRequest方法的最后一个参数不是需要的io.Reader类型的!会报错
req, err = http.NewRequest(requestMethod, url, requestBody)
if err != nil {
return "", err
}
res, err := client.Do(req)
if err != nil {
return "", err
}
defer res.Body.Close()
body, err := ioutil.ReadAll(res.Body)
if err != nil {
return "", err
}
return string(body), nil
}
// 测试
func TestNilError(t *testing.T) {
// GET
if res, err := BaseRequestString("GET", "https://www.baidu.com", nil); err != nil {
fmt.Println("err>> ", err.Error())
} else {
fmt.Println("res>> ", res)
}
}
如果按照这种实现的方式,程序会上报一个错误:
panic: runtime error: invalid memory address or nil pointer dereference [recovered]
其实错误就出在了nil的类型不一样。
我们可以看到,在函数定义阶段,requestBody定义的是bytes.Reader类型的,也就是说外部传入的nil也是bytes.Reader类型的。
但是我们再在http.NewRequest方法中看一下它的源码:
// NewRequest wraps NewRequestWithContext using the background context.
func NewRequest(method, url string, body io.Reader) (*Request, error) {
return NewRequestWithContext(context.Background(), method, url, body)
}
在Go语言中,变量总是被一个定义明确的值初始化,即使接口类型也不例外。对于一个接口的零值就是它的类型和值的部分都是nil:
这就很明白了:两个nil值的value虽然都是nil,但是它们的type不同!所以将bytes.Reader类型的nil传入需要io.Reader类型的nil参数的位置,肯定会报错的!
解决:
requestBody
改为接口类型 requestBody interface{}
就可以了