GoLang - Передача nil в функцию, которая принимает интерфейс
Я наткнулся на кое-что, что недавно бросило меня за петлю в Голанге.
package main
import (
"net/http"
"bytes"
"fmt"
"io/ioutil"
)
func createRequest(method, uri string, data *bytes.Buffer) string {
req, err := http.NewRequest(method, uri, data)
if err != nil {
return ""
}
req.Close = true
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return ""
}
defer resp.Body.Close()
respBody, err := ioutil.ReadAll(resp.Body)
if err != nil {
return ""
}
return string(respBody)
}
func createRequestNoBody(method, uri string) string {
req, err := http.NewRequest(method, uri, nil)
if err != nil {
return ""
}
req.Close = true
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return ""
}
defer resp.Body.Close()
respBody, err := ioutil.ReadAll(resp.Body)
if err != nil {
return ""
}
return string(respBody)
}
func main() {
data := createRequestNoBody("GET", "http://google.com")
if len(data) != 0 {
fmt.Println("First Request Ok")
}
data = createRequest("GET", "https://google.com", nil)
if len(data) != 0 {
fmt.Println("Second Request OK")
}
}
Этот код работает в createRequestNoBody
функция, когда ноль передается непосредственно http.NewRequest
но это вызывает панику при звонке createRequest
с *bytes.Buffer
установлен в nil
в вызывающей функции.
Функция NewRequest в библиотеке http имеет следующий прототип:
func NewRequest(method, urlStr string, body io.Reader) (*Request, error)
куда io.Reader
это интерфейс.
Я не уверен, почему ноль, передаваемый через переменную, может вызвать body
в NewRequest стать не ноль.
Может кто-нибудь объяснить, почему createRequest
метод приводит к панике? Как ноль параметр в data = createRequest("GET", "https://google.com", nil)
становится ноль внутри NewRequest
метод?
1 ответ
@JimB был прав в своем комментарии. Этот фрагмент кода ниже показывает, что тип объекта действительно (*bytes.Buffer, nil)
package main
import (
"bytes"
"fmt"
"reflect"
"errors"
"io"
)
func NewRequest(method, urlStr string, body io.Reader) (error) {
if body == nil {
fmt.Println("Body Is Nil")
return nil
}
fmt.Println(reflect.TypeOf(body).Elem())
return errors.New("NOT NIL")
}
func createRequest(method, uri string, data *bytes.Buffer) string {
fmt.Println("Type Of data is ", reflect.TypeOf(data).Elem())
if data == nil {
fmt.Println("data is nil")
}
err := NewRequest(method, uri, data)
if err != nil {
return err.Error()
}
return "OK"
}
func createRequestNoBody(method, uri string) string {
err := NewRequest(method, uri, nil)
if err != nil {
return err.Error()
}
return "OK"
}
func main() {
data := createRequestNoBody("GET", "http://google.com")
if len(data) != 0 {
fmt.Println("First Request Ok")
}
data = createRequest("GET", "https://google.com", nil)
if len(data) != 0 {
fmt.Println("Second Request Not OK")
}
}
Результат запуска выглядит так:
Body Is Nil
First Request Ok
Type Of data is bytes.Buffer
data is nil
bytes.Buffer
Second Request Not OK
поскольку body io.Reader
интерфейс, а не указатель на определенный тип, когда вы передаете nil
указатель типа bytes.Buffer
это будет не nil
интерфейс.