I am trying to write a function with a parameter of type *io.Reader
func ReadSomething(r *io.Reader) {
<do something with a reader>
}
but then when I try to pass in a pointer to a reader closer to it
func GetWebPage() {
resp, _ := http.Get(<url>)
ReadSomething(&(resp.Body))
}
I get the following error: cannot use &(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
?
CodePudding user response:
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.
CodePudding user response:
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.