Carl
Carl

Reputation: 77

Pointer to struct satisfy interface

I scanned the Revel framework's Go code and it seems that pointers satisfy interface requirements. See the snippets below.

type Result interface {
    Apply(req *Request, resp *Response)
}

type RenderTextResult struct {
    text string
}

func (r RenderTextResult) Apply(req *Request, resp *Response) {
    resp.WriteHeader(http.StatusOK, "text/plain; charset=utf-8")
    resp.Out.Write([]byte(r.text))
}

func (c *Controller) RenderText(text string, objs ...interface{}) Result {
    finalText := text
    if len(objs) > 0 {
        finalText = fmt.Sprintf(text, objs...)
    }
    return &RenderTextResult{finalText}
}

What's the reasoning behind this? The framework is returning a struct value instead of a struct pointer for rendering JSON, though:

type RenderJsonResult struct {
    obj      interface{}
    callback string
}

// Uses encoding/xml.Marshal to return XML to the client.
func (c *Controller) RenderXml(o interface{}) Result {
    return RenderXmlResult{o}
}

I can't seem to grasp the subtle (?) differences.

Upvotes: 3

Views: 132

Answers (3)

James Henstridge
James Henstridge

Reputation: 43949

Methods associated with a type are also available on pointers to that type. So if r is a *RenderTextResult variable, then r.Apply(...) is equivalent to (*r).Apply().

In most respects, the Apply method will act like any method associated with *RenderTextResult directly, although it won't be able to modify the contents of the struct, since it receives a copy of the struct rather than a pointer to the original.

This means that the methods on RenderTextResult can be used to let *RenderTextResult satisfy the Result interface.

Upvotes: 2

ChrisH
ChrisH

Reputation: 4826

Yes, pointers implicitly have all the methods of the type they point to. See the FAQ sections "Why do T and *T have different method sets?" and "Methods on values or pointers?"

Upvotes: 3

nemo
nemo

Reputation: 57757

Any named type can satisfy an interface. It does not matter whether the type is a pointer, a channel or a function value as long as it implements the methods the interface demands.

Example of a function satisfying an interface (play):

type Printer interface {
    Print(string)
}

type funcPrinter func() string

func (f funcPrinter) Print(s string) { 
     fmt.Println(s + f()) 
}

This leaves the question why one would return a pointer rather than a value or vice versa. If you pass objects around all the time then it is a good idea to use pointers as they are always of a small fixed length instead of all the values.

The following line results in having the struct copied to the caller:

return RenderXmlResult{o}

While this call will return a pointer to the struct placed somewhere in the heap.

return &RenderXmlResult{o}

Upvotes: 1

Related Questions