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
- Go Time Layout Converter — strftime to Go, and back — Convert a C strftime format string to a Go reference layout and back, directive by directive, with every unmappable directive named rather than guessed.
- Go Struct Field Alignment — offsets, padding, and what reordering saves — Paste a struct and get every field's offset, the padding between them, the total size, and a reordered version with the saving — for the architecture you choose.
- Go Slice Growth — what append actually does to the capacity — Watch a slice's capacity grow append by append: the formula's answer, the allocator's rounding, the size class it lands in, and the bytes left behind.
- Go Goroutine Dump Analyzer — read a SIGQUIT or panic stack dump — Paste a goroutine dump and get it grouped by state and by stack, with wait durations and the stacks held by far more goroutines than they should be.