Go Method Sets: pointer receiver vs value receiver

Paste a type and an interface. This computes the method set of T and of *T with go/types — the compiler's own implementation — and says precisely why one satisfies the interface and the other does not.

Nothing you paste is transmitted. There is no endpoint behind this page: the Go that type-checks your code is compiled to WebAssembly and runs in this tab, so your source never leaves the browser.

This page loads the larger of the section's two modules, because it carries the compiler's own front end — go/ast, go/parser and go/types. It is fetched once, when you open the page.

Start from one of these

    The rule, in two lines

    Everything about this error follows from one asymmetry:

    The method set of T contains the methods declared with receiver T. The method set of *T contains the methods declared with receiver T or *T.

    So a pointer-receiver method is in the method set of *T and not in the method set of T. An interface is satisfied by whichever of the two has the methods it needs. That is the whole rule; there are no exceptions to it.

    Why your method “works” and the interface still fails

    This is the part that makes the error feel arbitrary. Given var c Counter and a String method with a pointer receiver, c.String() compiles. It compiles because the compiler rewrites it to (&c).String() whenever c is addressable — a variable is, a map element is not.

    That rewrite is a convenience at the call site. It has nothing to do with method sets. Satisfying an interface is a question about the method set of the type, asked without reference to any particular value, so no addressability rule can help: the compiler would have to take the address of a value it has not been given.

    Which is exactly why a type whose methods all work when you call them directly can still fail to satisfy an interface, and why the error arrives at the assignment rather than at the method.

    Embedding promotes more than people expect

    The reason this page asks go/types rather than reading your receivers is embedding. If Outer embeds Inner by value, Inner's pointer-receiver methods are in the method set of *Outer only. If Outer embeds *Inner, those same methods are in the method set of Outer — the plain value — because the embedded pointer is already addressable without taking the address of anything.

    One of the examples above is exactly that pair, side by side.

    What this does not do

    It does not resolve imports. Type-checking a snippet that imports a package means reading that package, and there is nothing here to read it from — no file system, no module cache. Substituting a stand-in for an imported type would be a guess, and a wrong guess here does not produce an error; it produces a confident wrong answer about whether your type satisfies an interface. So an import is named and refused, and what you do instead is paste the interface's declaration, which for almost every interface this question comes up about is three lines.

    The other tools