英文:
Golang Type system inconsistency (http package)
问题
我正在努力理解Go语言的类型系统,有几个问题让我感到困惑。
所以我一直在使用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))
}
这不是关于不需要convert函数的事实,而是响应体的类型是io.Closer,而ioutil.ReadAll需要一个io.Reader类型的参数,然而我可以在一个实例中传递它,但在另一个实例中却不能。我是否遗漏了某些神奇的事情?
我知道closer在技术上通过实现Read方法来传递reader接口,但这在函数和主体中都应该是正确的。
如果有任何见解,将不胜感激。
谢谢。
英文:
I am trying to wrap my head around the GoLang type system, and there area a few things the confuse me.
So I have been working on the http library to try to understand this and I have come across the following that makes no sense.
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))
}
this is not about the fact that the convert function is not needed it is the fact that the response body is of type io.closer and the ioutil.Readall takes a io.reader, yet I can pass it in, in one instance but not if in another. Is there something that I am missing that is magically happening.
I know that the closer technically passes the reader interface as it implements the the Read method but that should be true in both the function and the main body.
Any insight would be great.
Thanks
答案1
得分: 2
不,事实并非如此。Request.Body
的声明在http.Request
中:
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
,你不能在需要io.Reader
的地方使用closer
。它可能(在你的情况下是这样)存储的动态类型也实现了io.Reader
,但是不能保证这一点。就像这个例子中一样:
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
:
func convert(rc io.ReadCloser) ([]byte, error) {
body, err := ioutil.ReadAll(rc)
if err != nil {
return body, err
}
err = rc.Close()
return body, err
}
英文:
> it is the fact that the response body is of type io.closer
No, it is not. Declaration of Request.Body
is at http.Request
:
Body io.ReadCloser
The Request.Body
field is of type io.ReadCloser
, it is both an io.Reader
and an io.Closer
.
Since it is an io.Reader
(dynamic value of Request.Body
implements io.Reader
), you may use / pass it where an io.Reader
is required, e.g. to ioutil.ReadAll()
.
Since it also implements io.Closer
, you can also pass it where io.Closer
is required, like your convert()
function.
But inside convert the closer
param has static type io.Closer
, you can't use closer
where an in.Reader
is required. It might be (and in your case it is) that the dynamic type stored in closer
also implements io.Reader
, but there is no guarantee for this. Like in this example:
type mycloser int
func (mycloser) Close() error { return nil }
func main() {
var m io.Closer = mycloser(0)
convert(m)
}
In the above example closer
inside convert()
will hold a value of type mycloser
, which truly does not implement io.Reader
.
If your convert()
function intends to treat its parameter also as an io.Reader
, the parameter type should be 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
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论