-2

I have found many similar problem, but not what I want please see following codes.

(1)

var buf bytes.Buffer
fmt.Fprint(&buf,"test")

(2)

var w http.ResponseWriter
http.Error(w,http.StatusText(http.StatusBadRequest),http.StatusBadRequest)

both http.ResponseWriter and bytes.Buffer implement io.Writer interface, so I think they should have same behavior.

when I change to

http.Error(&w,http.StatusText(http.StatusBadRequest),http.StatusBadRequest)

jetbrains goland tell me

Cannot use '&w' (type *http.ResponseWriter) as type ResponseWriter

I wonder why buf have '&' can works, but another don't work?

I googled, somebody say when pass value to function, it can reference to &w

but another say if you pass a pointer, it can deference to value

from https://github.com/golang/go/wiki/MethodSets#variables

To make it easier to remember these rules, it may be helpful to simply consider the pointer- and value-receiver methods separately from the method set. It is legal to call a pointer-valued method on anything that is already a pointer or whose address can be taken (as is the case in the above example). It is legal to call a value method on anything which is a value or whose value can be dereferenced (as is the case with any pointer; this case is specified explicitly in the spec).

I am totally confused, I can't understand by myself. I wish you can help me, thank you!

nuclear
  • 3,181
  • 3
  • 19
  • 38
  • 2
    `bytes.Buffer` is a concrete type, `http.ResponseWriter` is an interface type. The note on pointer/value receivers for methods is unrelated. – Adrian Aug 28 '18 at 15:20
  • The function `http.Error` takes, specifically, a `http.ResponseWriter`, but you're passing a `*http.ResponseWriter` (as the error says). It's the wrong type for the function argument (not method receiver). – Adrian Aug 28 '18 at 15:22
  • If you see the definition `func Error(w ResponseWriter, error string, code int)` it requires `ResponseWriter` not a pointer to it. This is the reason behind error not the one you are considering. – Himanshu Aug 28 '18 at 15:22
  • @Adrian from my understand what's you said, interface don't have &interface, right? when use interface, we just pass it directly? – nuclear Aug 28 '18 at 15:34
  • @toffee no that is not what it means, it means that if a function has a type other than a interface you have to satisfy that. – Himanshu Aug 28 '18 at 15:41
  • 1
    You really should dig into Go's type system. It is not about magically or randomly putting & and * before stuff. You have to understand the different types like struct types (bytes.Buffer) and interface types (http.ResponseWriter) and understand method sets. SO is not the right place to get this answers. You might try reddit or golang-nuts. – Volker Aug 28 '18 at 15:47
  • 1
    Both are `io.Writer`s, yes, but both are *not* `http.ResponseWriter`s. – Jonathan Hall Aug 28 '18 at 15:56

1 Answers1

1

Maybe I can try to explain more detailed what all the very good comments are already saying:

Interfaces are (mostly) pointers in go

Interfaces in go are implemented (satisfied) if another type implements all the methods an interface defines. Usually that is done by adding the methods on the pointer of the type, not the type directly.

type SomeInterface interface {
    SomeMethod string
}

type SomeStruct struct {} // often is a struct but does not have to be

// a method on the structs pointer
func (s *SomeStruct) SomeMethod string {
    return ""
}

The results of this:

  1. SomeStruct does NOT implement SomeInterface, *SomeStruct does!
  2. An Interface is (usually) already a pointer.

Your example

var b bytes.Buffer
fmt.Fprintf(&b, "some text")

var w http.ResponseWriter
http.Error(w, "some error", 1)

Variable b of type bytes.Buffer is a struct as you can see from the source code:

type Buffer struct {
    buf       []byte   // contents are the bytes buf[off : len(buf)]
    off       int      // read at &buf[off], write at &buf[len(buf)]
    bootstrap [64]byte // memory to hold first slice; helps small buffers avoid allocation.
    lastRead  readOp   // last read operation, so that Unread* can work correctly.

    // FIXME: it would be advisable to align Buffer to cachelines to avoid false
    // sharing.
}

If you want to use it as type io.Writer (interface) you need to get a pointer of bytes.Buffer as (usually) pointer methods are used in go: fmt.Fprintf(&b, "some text")

Variable w of type http.ResponseWriter is an interface:

type ResponseWriter interface {
    Header() Header
    Write([]byte) (int, error)
    WriteHeader(statusCode int)
}

Since interfaces are (usually) already pointers to some underlying implementation we can use it without taking a pointer: http.Error(w, "some error", 1).

Interface initialisation

An interface itself cannot be initialised and used! You always need a struct or other type to implement the interface and then you can initialise that and use it as type SomeInterface. For example here is the implementation of gin for a http.ResponseWriter. As you can see from the code it uses pointer receivers for its methods. So http.ResponseWriter is already a pointer to a struct.

Disclaimer

This is just one way of trying to make this complex topic sound simple (hopefully). This is not a technically complete or completely accurate explanation. Trying to stay simple and yet as accurate as possible.

TehSphinX
  • 6,536
  • 1
  • 24
  • 34