Search code examples
pointersgointerfacepass-by-referencepass-by-value

golang address of interface and interface difference


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!


Solution

  • 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.