drzfz9995 2017-06-05 13:37
浏览 169
已采纳

“ <类型>是接口的指针,而不是接口”的困惑

Dear fellow developers,

I've got 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.

  • 写回答

2条回答 默认 最新

  • dongle2627 2017-06-05 16:01
    关注

    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 {
        Foo()
    }
    
    type Foo struct{}
    
    func (f Foo) Foo() {}
    
    func main() {
        var f1 Foo
        var f2 *Foo = &Foo{}
    
        DoFoo(f1)
        DoFoo(f2)
    }
    
    func DoFoo(f Fooer) {
        fmt.Printf("[%T] %+v
    ", f, f)
    }
    

    Output:

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

    https://play.golang.org/p/BGV9d1-IRW

    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) Foo(), not func (f *Foo) Foo()) 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:

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 求daily translation(DT)偏差订正方法的代码
  • ¥15 js调用html页面需要隐藏某个按钮
  • ¥15 ads仿真结果在圆图上是怎么读数的
  • ¥20 Cotex M3的调试和程序执行方式是什么样的?
  • ¥20 java项目连接sqlserver时报ssl相关错误
  • ¥15 一道python难题3
  • ¥15 牛顿斯科特系数表表示
  • ¥15 arduino 步进电机
  • ¥20 程序进入HardFault_Handler
  • ¥15 关于#python#的问题:自动化测试