我正在努力将自己的头围在GoLang类型系统上,还有一些使我感到困惑的地方。

因此,我一直在研究http库以尝试理解这一点,并且遇到了以下毫无意义的事情。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package main

import (
   "net/http"
   "fmt"
   "io/ioutil"
   "io"
)

func convert(closer io.Closer) ([]byte) {
    body, _ := ioutil.ReadAll(closer);
    return body
}

func main() {

    client := &http.Client{}
    req, _ := http.NewRequest("GET","https://www.google.com", nil)

    response, _ := client.Do(req);

    body, _ := ioutil.ReadAll(response.Body)

    fmt.Println(body);
    fmt.Println(convert(response.Body))

}

围棋场

这不是不需要转换函数的事实,而是响应主体是io.closer和ioutil.Readall类型的io.reader,但是我可以在一种情况下将其传递给我,而不是 如果在另一个。 有什么我梦missing以求的事情正在发生。

我知道,在实现读方法时,从技术上讲,更近的传递给阅读器接口,但这在函数和主体上都应如此。

任何见识都会很棒。

谢谢

  • 为什么要让convert接受io.Closer(如果应该为io.Reader)?
  • is the fact that the response body is of type io.closer ... golang.org/src/net/http/response.go响应的正文为io.ReadCloser类型。
  • 抱歉,我在这里犯了一个小错误,http正文的默认类型是io.ReadCloser,它来自主包golang.org/pkg/net/http/#Response。

it is the fact that the response body is of type io.closer

不它不是。 Request.Body的声明位于http.Request

1
Body io.ReadCloser

Request.Body字段的类型为io.ReadCloser,它既是io.Reader又是io.Closer

由于它是io.Reader(Request.Body的动态值实现了io.Reader),因此可以在需要io.Reader的地方使用/传递它,例如 到ioutil.ReadAll()

由于它还实现了io.Closer,因此您也可以将其传递到需要io.Closer的位置,例如convert()函数。

但是在convert closer参数内部具有静态类型io.Closer的情况下,不能在需要in.Reader的地方使用closercloser中存储的动态类型也可能(并且在您的情况下)也实现了io.Reader,但是对此不能保证。 像这个例子:

1
2
3
4
5
6
7
8
type mycloser int

func (mycloser) Close() error { return nil }

func main() {
    var m io.Closer = mycloser(0)
    convert(m)
}

在上面的示例中,convert()中的closer将保存类型为mycloser的值,该值实际上未实现io.Reader

如果您的convert()函数打算将其参数也视为io.Reader,则参数类型应为io.ReadCloser

1
2
3
4
5
6
7
8
func convert(rc io.ReadCloser) ([]byte, error) {
    body, err := ioutil.ReadAll(rc)
    if err != nil {
        return body, err
    }
    err = rc.Close()
    return body, err
}