我正试图围绕GoLang类型系统,并且有一些事情让我感到困惑。
所以我一直在研究http库以试图理解这一点,而且我发现以下内容毫无意义。
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,但是我可以将它传递给一个实例但不在另一个实例中。是否有一些我错过的神奇事件。
我知道技术上更接近于读取器接口,因为它实现了Read方法,但在函数和主体中都应该是真的。
任何见解都会很棒。
由于
答案 0 :(得分:2)
事实上,响应主体的类型为io.closer
不,不是。 Request.Body
声明位于http://localhost/WebUI/Scripts/uicontrols/basic/fastsearch.js:
Body io.ReadCloser
Request.Body
字段的类型为Forked JSFiddle,它既是http.Request
又是io.ReadCloser
。
由于它是io.Reader
(动态值Request.Body
实施io.Reader
),您可以在需要io.Reader
的位置使用/传递它,例如到io.Reader
。
由于它还实现了io.Closer
,您也可以将其传递到需要io.Closer
的地方,例如您的convert()
功能。
但是在内部转换中,closer
param具有静态类型io.Closer
,您无法在需要closer
的情况下使用in.Reader
。存储在closer
中的动态类型也可以(并且在您的情况下)也实现io.Reader
,但不能保证这一点。就像在这个例子中一样:
type mycloser int
func (mycloser) Close() error { return nil }
func main() {
var m io.Closer = mycloser(0)
convert(m)
}
在上面的示例中,closer
中的convert()
将保留mycloser
类型的值,该值实际上不会实现io.Reader
。
如果您的convert()
函数打算将其参数也视为io.Reader
,则参数类型应为io.ReadCloser
:
func convert(rc io.ReadCloser) ([]byte, error) {
body, err := ioutil.ReadAll(rc)
if err != nil {
return body, err
}
err = rc.Close()
return body, err
}