199

I have this problem which seems a bit weird to me. Take a look at this snippet of code:

package coreinterfaces

type FilterInterface interface {
    Filter(s *string) bool
}

type FieldFilter struct {
    Key string
    Val string
}

func (ff *FieldFilter) Filter(s *string) bool {
    // Some code
}

type FilterMapInterface interface {
    AddFilter(f *FilterInterface) uuid.UUID     
    RemoveFilter(i uuid.UUID)                   
    GetFilterByID(i uuid.UUID) *FilterInterface
}

type FilterMap struct {
    mutex   sync.Mutex
    Filters map[uuid.UUID]FilterInterface
}

func (fp *FilterMap) AddFilter(f *FilterInterface) uuid.UUID {
    // Some code
}

func (fp *FilterMap) RemoveFilter(i uuid.UUID) {
    // Some code
}

func (fp *FilterMap) GetFilterByID(i uuid.UUID) *FilterInterface {
    // Some code
}

On some other package, I have the following code:

func DoFilter() {
    fieldfilter := &coreinterfaces.FieldFilter{Key: "app", Val: "152511"}
    filtermap := &coreinterfaces.FilterMap{}
    _ = filtermap.AddFilter(fieldfilter) // <--- Exception is raised here
}

The run-time won't accept the line mentioned because

"cannot use fieldfilter (type *coreinterfaces.FieldFilter) as type *coreinterfaces.FilterInterface in argument to fieldint.AddFilter: *coreinterfaces.FilterInterface is pointer to interface, not interface"

However, when changing the code to:

func DoBid() error {
    bs := string(b)
    var ifilterfield coreinterfaces.FilterInterface
    fieldfilter := &coreinterfaces.FieldFilter{Key: "app", Val: "152511"}
    ifilterfield = fieldfilter
    filtermap := &coreinterfaces.FilterMap{}
    _ = filtermap.AddFilter(&ifilterfield)
}

Everything is alright and when debugging the application it really seems to include

I'm a bit confused on this topic. When looking at other blog posts and stack overflow threads discussing this exact same issue (for example - This, or This) the first snippet which raises this exception should work, because both fieldfilter and fieldmap are initialized as pointers to interfaces, rather than value of interfaces. I haven't been able to wrap my head around what actually happens here that I need to change in order for me not to declare a FieldInterface and assign the implementation for that interface. There must be an elegant way to do this.

Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
0rka
  • 2,246
  • 2
  • 11
  • 20
  • When changing `* FilterInterface` to `FilterInterface` The line `_ = filtermap.AddFilter(fieldfilter)` now raises this: **cannot use fieldfilter (type coreinterfaces.FieldFilter) as type coreinterfaces.FilterInterface in argument to filtermap.AddFilter: coreinterfaces.FieldFilter does not implement coreinterfaces.FilterInterface (Filter method has pointer receiver)** However when changing the line to `_ = filtermap.AddFilter(&fieldfilter)` it works. What happens here? why is that? – 0rka Jun 05 '17 at 14:13
  • 3
    Because the methods that implement the interface have pointer receivers. Passing a value, it does not implement the interface; passing a pointer, it does, because the methods then apply. Generally speaking, when dealing with interfaces, you pass a pointer to a struct to a function that expects an interface. You almost never want a pointer to an interface in any scenario. – Adrian Jun 05 '17 at 15:09
  • 2
    I understand your point, but by changing the parameter value from `* FilterInterface` to a struct that implements this interface, this breaks the idea of passing interfaces to functions. What I wanted to accomplish is not being bound to what struct I was passing, but rather **any** struct that implements the interface I'm interested to use. Any code changes you might think be more efficient or up to standards for me to do? I'll be glad to use some code review services :) – 0rka Jun 05 '17 at 15:15
  • 3
    Your function should accept an interface argument (not pointer to interface). The caller should pass in a pointer to a struct that implements the interface. This does not "break the idea of passing interfaces to functions" - the function still takes an interface, you're passing in a concretion which implements the interface. – Adrian Jun 05 '17 at 15:38

2 Answers2

287

So you're confusing two concepts here. A pointer to a struct and a pointer to an interface are not the same. An interface can store either a struct directly or a pointer to a struct. In the latter case, you still just use the interface directly, not a pointer to the interface. For example:

type Fooer interface {
    Dummy()
}

type Foo struct{}

func (f Foo) Dummy() {}

func main() {
    var f1 Foo
    var f2 *Foo = &Foo{}

    DoFoo(f1)
    DoFoo(f2)
}

func DoFoo(f Fooer) {
    fmt.Printf("[%T] %+v\n", f, f)
}

Output:

[main.Foo] {}
[*main.Foo] &{}

https://play.golang.org/p/I7H_pv5H3Xl

In both cases, the f variable in DoFoo is just an interface, not a pointer to an interface. However, when storing f2, the interface holds a pointer to a Foo structure.

Pointers to interfaces are almost never useful. In fact, the Go runtime was specifically changed a few versions back to no longer automatically dereference interface pointers (like it does for structure pointers), to discourage their use. In the overwhelming majority of cases, a pointer to an interface reflects a misunderstanding of how interfaces are supposed to work.

However, there is a limitation on interfaces. If you pass a structure directly into an interface, only value methods of that type (ie. func (f Foo) Dummy(), not func (f *Foo) Dummy()) can be used to fulfill the interface. This is because you're storing a copy of the original structure in the interface, so pointer methods would have unexpected effects (ie. unable to alter the original structure). Thus the default rule of thumb is to store pointers to structures in interfaces, unless there's a compelling reason not to.

Specifically with your code, if you change the AddFilter function signature to:

func (fp *FilterMap) AddFilter(f FilterInterface) uuid.UUID

And the GetFilterByID signature to:

func (fp *FilterMap) GetFilterByID(i uuid.UUID) FilterInterface

Your code will work as expected. fieldfilter is of type *FieldFilter, which fullfills the FilterInterface interface type, and thus AddFilter will accept it.

Here's a couple of good references for understanding how methods, types, and interfaces work and integrate with each other in Go:

kubanczyk
  • 5,184
  • 1
  • 41
  • 52
Kaedys
  • 9,600
  • 1
  • 33
  • 40
  • 1
    "This is because you're storing a copy of the original structure in the interface, so pointer methods would have unexpected effects (ie. unable to alter the original structure)" - this doesn't make sense as the reason for the limitation. After all, the only copy may have been stored in the interface all along. – WPWoodJr Feb 20 '18 at 01:15
  • Your answer there makes no sense. You're assuming that the location at which the concrete type stored in the interface does not change when you change what's stored there, which is not the case, and that should be obvious if you're storing something with a different memory layout. What you're not getting about my pointer comment is that a pointer receiver method on a concrete type can _always_ modify the receiver it is being called on. A value stored in an interface forces a copy that you cannot then get a reference to, so pointer receivers _cannot_ modify the original, period. – Kaedys Feb 20 '18 at 16:09
  • @Kaedys Is there any usecase we have to use pointer to interface? – Kevin Jun 19 '21 at 14:34
  • Almost never, but only "almost". The sole use case (at least that I can think of) where it can be valuable is if you need to change what's stored in an interface by reference. However, it's nearly always better design to _return_ the new or altered interface, rather than mutate it in-place, to avoid surprise side-effects. – Kaedys Jun 21 '21 at 19:20
  • thanks! this whole pointer vs value thing in go is really confusing, especially in this case, wonder if there were good reasons to design it this way – axk Jul 25 '21 at 17:36
  • 1
    Thanks for the answer. `If you pass a structure directly into an interface` what do you mean by this line ? – Vishal Seshagiri Nov 01 '21 at 15:55
  • 2
    `var v interface{} = MyCoolStruct{}` versus `var v interface{} = &MyCoolStruct{}`. The former is passing the struct/concrete type into the interface, while the latter is passing a pointer to it instead. In the former case, only value methods (`func (m MyCoolStruct) A()`) can be used to fulfill the interface methods, while in the later both value methods _and_ pointer methods (`func (m *MyCoolStruct) B()`) can be used. – Kaedys Nov 08 '21 at 18:43
  • The first link is no longer available. Here is a web archive link to it -> [link](http://web.archive.org/web/20170120032933/https://medium.com/@agileseeker/go-interfaces-pointers-4d1d98d5c9c6) – Marko Jul 03 '23 at 13:44
  • Does this mean that defining a struct that implements an interface, but mixes value and pointer receivers of the interface methods, will not be usable as an argument? – Marko Jul 03 '23 at 15:33
  • 1
    @Marko: The methods with value receivers can still be called on pointer receivers, and (therefore) the pointers implement the interface. So you can write `var myVariable MyInterfaceType = &MyStructType{ ... }`, and then call the methods on `myVariable`. What you *can't* do is then write `var myPointer = &myVariable` and then call methods on `myPointer`; but that limitation would apply regardless of how you defined the struct. – ruakh Jul 09 '23 at 05:46
20
GetFilterByID(i uuid.UUID) *FilterInterface

When I get this error, it's usually because I'm specifying a pointer to an interface instead of an interface ( that will actually be a pointer to my struct that fulfills the interface ).

There's a valid use for *interface{...} but more commonly I just am thinking 'this is a pointer' instead of 'this is an interface which happens to be a pointer in the code I'm writing'

erik258
  • 14,701
  • 2
  • 25
  • 31
  • 2
    This one helped me faster than the more detailed answer above, +1; I wish go used the `IThing` style of interface naming -- `___er` isn't clear enough for me to be able to spot an interface quickly – jcollum Dec 02 '20 at 22:11