可以将 *io.ReadCloser 传递给类型为 *io.Reader 的参数吗?

huangapple go评论83阅读模式
英文:

Can I pass an *io.ReadCloser to a parameter with the type of *io.Reader

问题

我正在尝试编写一个带有类型为*io.Reader的参数的函数。

func ReadSomething(r *io.Reader) {
    // 使用读取器进行一些操作
}

但是当我尝试将一个更接近它的读取器的指针传递给它时:

func GetWebPage() {
    resp, _ := http.Get(<url>)
    ReadSomething(&(resp.Body))
}

我得到以下错误:cannot use &(resp.Body) (value of type *io.ReadCloser) as *io.Reader value

这对我来说毫无意义,一个解引用的读取器指针类型应该实现了Reader的方法,那么为什么我不能将它作为参数传递给一个期望io.Reader指针的函数呢?

英文:

I am trying to write a function with a parameter of type *io.Reader

func ReadSomething(r *io.Reader) {
    &lt;do something with a reader&gt;
}

but then when I try to pass in a pointer to a reader closer to it

func GetWebPage() {
    resp, _ := http.Get(&lt;url&gt;)
    ReadSomething(&amp;(resp.Body))
}

I get the following error: cannot use &amp;(resp.Body) (value of type *io.ReadCloser) as *io.Reader value.

This makes no sense to me, a dereferenced pointer to a read closer type should implement the methods of Reader, so why am I not able then to pass it in as an argument to a function that expects a pointer to an io.Reader?

答案1

得分: 3

io.ReadCloser 是一个接口类型,它是 io.Reader 接口类型的超集。所以,每当需要一个 io.Reader 时,你可以传递一个 io.ReadCloser 的值。

*io.Reader 并不是一个接口类型,它是一个指针(指向接口的指针),所以你不能传递 *io.ReadCloser

请注意,这些函数签名设计得很糟糕。你很少需要一个指向接口的指针(当你确实需要时,你会知道,可以参考这个示例)。只需使用接口类型,接口可以包装指针(如果需要的话)。

英文:

io.ReadCloser is an interface type that is a superset of io.Reader interface type. So whenever an io.Reader is required, you may pass a value of io.ReadCloser.

*io.Reader is not an interface type though, it's a pointer (a pointer to interface), so you can't pass *io.ReadCloser.

Please note that these function signatures are a terrible design. You rarely need a pointer to interface (you'll know when you do, see this for an example). Just use interface types, interfaces may wrap pointers if needed.

答案2

得分: 2

在Go语言中,有一个普遍的误解,即接口比它们实际上更具有神奇和粘合性。作为起点,不同类型之间的所有转换都必须是显式的,而接口是不同的类型。

接口只是对这个规则的一个狭窄例外:

在Go语言规范中的可赋值性规则(也适用于参数传递)中有这样的定义:
> 如果一个值x可以赋值给类型T("x is assignable to T"),那么[...]
>
> - T是一个接口类型,并且x实现了T。

换句话说,简单明了地说:
> 如果x实现了T,那么x可以赋值给T。

这实际上就是整个例外的全部内容,并且它并不试图广泛地将接口、实现和相关结构融合在一起。一旦你通过指针间接引用接口值,你就已经超出了枚举的范围。

英文:

It's a common misconception in Go that interfaces are more magical and gluey than they really are. As a starting point, all conversions between distinct types must be explicit, and interfaces are distinct types.

Interfaces only carve out a narrow exception to this rule:

Assignability Rules in the Go Specification (which extends to parameter passing).
> A value x is assignable to a variable of type T ("x is assignable to T") if [...]
>
> - T is an interface type and x implements T.

Or in other words, simple and plain:
> x is assignable to T if x implements T.

That's really the whole entire exception, and it makes no expansive effort to generally mesh interfaces, implementations, and structures thereof. As soon as you indirect your interface value through a pointer, you have stepped out of the enumerated territory.

huangapple
  • 本文由 发表于 2022年2月16日 15:35:49
  • 转载请务必保留本文链接:https://go.coder-hub.com/71137875.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定