2016-09-21 117 views
0

最近,我偶然發現了一些讓我在golang中循環的東西。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") 
    } 
} 

此代碼時無直接傳遞到http.NewRequest但隨着*bytes.Buffer設置爲nil調用函數中調用createRequest時,它會產生一個恐慌工作在createRequestNoBody功能。

在HTTP庫NewRequest函數的原型如下:

func NewRequest(method, urlStr string, body io.Reader) (*Request, error)

io.Reader是一個接口。

我不確定爲什麼通過變量的nil會導致NewRequest中的body變爲非零。

任何人都可以解釋爲什麼createRequest方法導致恐慌?在NewRequest方法中,data = createRequest("GET", "https://google.com", nil)的nil參數如何變爲非零?

+3

請參見[常見問題解答:爲什麼我的nil錯誤值不等於零?](https://golang.org/doc/faq#nil_error) – JimB

+4

[隱藏nil值,理解爲什麼golang在這裏失敗] (http://stackoverflow.com/questions/29138591/hiding-nil-values-understanding-why-golang-fails-here) – icza

+0

感謝鏈接@JimB,這的確解釋了它。當它在createRequest函數之間傳遞時,它在接口中獲得一個類型,並通過(* bytes.Buffer,nil)而不是(nil,nil)傳遞給下一個函數。 在調用NewRequest(nil,nil)或(* bytes.Buffer,nil)之前是'data'的值。我不確定它什麼時候變成(* bytes.Buffer,nil)是問題所在。 – soluwalana

回答

0

@JimB在他的評論中是正確的。下面這段代碼示出了對象的類型確實(* bytes.Buffer,無)

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接口。

相關問題