Half of your question depends on whether your value is addressable or not:
For an operand x
of type T
, the address operation &x
generates a
pointer of type *T
to x
. The operand must be addressable, that is,
either:
- a variable,
- pointer indirection, or
- slice indexing operation; or
- a field selector of an addressable struct operand; or
- an array indexing operation of an addressable array.
As an exception to the addressability requirement, x
may also be a
(possibly parenthesized) composite literal.
— Address operators
Bar{}
is a composite literal, thus it is not addressable. You may type &Bar{}
to create an object of type *Bar
, but that is listed as "an exception to the addressability requirement", reinforcing the idea that Bar{}
is not addressable in itself.
Variable b
of type Bar
can invoke b.foo()
despite Bar.foo()
requiring a pointer receiver for a good reason:
A method call x.m()
is valid if the method set of (the type of) x
contains m
and the argument list can be assigned to the parameter
list of m
. If x
is addressable and &x
's method set contains m
,
x.m()
is shorthand for (&x).m()
— Calls
However, that does not mean Bar.foo()
is in the method set of b
. This is because b
has type Bar
while Bar.foo()
receives a value of type *Bar
:
A type may have a method set associated with it. The method set of an
interface type is its interface. The method set of any other type T
consists of all methods declared with receiver type T
. The method
set of the corresponding pointer type *T
is the set of all methods
declared with receiver *T
or T
(that is, it also contains the
method set of T
).
— from Method sets
Because the method sets of b
and the Foo
interface differ, you cannot use var foo Foo = b
, despite b.foo()
being converted to (&b).foo()
by the compiler. Otherwise, var foo Foo = Bar{}
would work. You may, however, use either of the following since Bar.foo()
receives a *Bar
:
var foo Foo = &b
var foo Foo = &Bar{}