"<类型>是指向接口的指针,而不是接口“混乱 [英] "<type> is pointer to interface, not interface" confusion

查看:198
本文介绍了"<类型>是指向接口的指针,而不是接口“混乱的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

亲爱的开发者们,

我有这个问题,对我来说似乎有点奇怪。看看这段代码:

 包核心接口

类型FilterInterface接口{
过滤器(s *字符串)bool
}

类型FieldFilter结构{
键字符串
字符串
}

func(ff * FieldFilter)Filter(s * string)bool {
//某些代码
}

类型FilterMapInterface接口{
AddFilter(f * FilterInterface)uuid .UUID
RemoveFilter(我uuid.UUID)
GetFilterByID(我uuid.UUID)* FilterInterface
}

类型FilterMap结构{
互斥体同步。互斥体
过滤器映射[uuid.UUID] FilterInterface
}

func(fp * FilterMap)AddFilter(f * FilterInterface)uuid.UUID {
//一些代码

$ b $ func(fp * FilterMap)RemoveFilter(i uuid.UUID){
//一些代码
}

func FilterInterface {
//一些代码
}

在其他一些软件包中,我必须遵循以下代码:

  func DoFilter(){
fieldfilter:=& coreinterfaces.FieldFilter {Key:app,Val:152511}
filtermap:=& coreinterfaces.FilterMap {}
_ = filtermap.AddFilter(fieldfilter)//< ; ---这里提出的异常
}

运行时不会接受因为

lockquote

不能使用fieldfilter(type * coreinterfaces.FieldFilter)作为类型
* coreinterfaces.FilterInterface in argument to fieldint.AddFilter:
* coreinterfaces.FilterInterface是指向接口的指针,而不是接口

但是,将代码更改为:

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

一切都很好,在调试应用程序时,它似乎真的包含了一些内容。

我对这个主题有点困惑。在讨论其他博客文章和堆栈溢出线程时,讨论这个完全相同的问题(例如 - 这个,或
这个)引发这个异常的第一个片段应该可以工作,因为fieldfilter和fieldmap都被初始化为接口的指针,而不是接口的值。我一直无法围绕我在这里实际发生的事情需要改变,以便我不声明FieldInterface并为该接口分配实现。必须有一个优雅的方式来做到这一点。

解决方案

所以你在这里混淆了两个概念。指向结构的指针和指向接口的指针是不一样的。一个接口可以直接存储一个结构指向结构的指针。在后一种情况下,您仍然直接使用该接口,而不是指向该接口的指针。例如:

  type Fooer接口{
Foo()
}

类型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 \ n,f,f)
}

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

在这两种情况下, DoFoo f 变量$ c>只是一个接口,不是指向接口的指针。但是,当存储 f2 时,接口包含指向 Foo 结构的指针。 / p>

指向接口的指针几乎是从不 有用的。实际上,Go运行时特别改变了几个版本,不再自动解引用接口指针(就像它为结构指针所做的那样),以阻止它们的使用。在绝大多数情况下,指向接口的指针反映了对接口应该如何工作的误解。



但是,接口有一个限制。如果你将一个结构直接传递给接口,那么只有该类型的 value 方法(即 func(f Foo)Foo(),而不是 func(f * Foo)Foo())可用于完成界面。这是因为你要在接口中存储原始结构的副本,所以指针方法会产生意想不到的效果(即无法更改原始结构)。因此,默认的经验法则是存储指向结构的指针,除非有令人信服的理由。



特别是对于您的代码,如果将AddFilter函数签名更改为:

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

以及GetFilterByID签名为:

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

代码将按预期工作。 fieldfilter 类型为 * FieldFilter ,它满足 FilterInterface 接口类型,因此 AddFilter 将接受它。



以下是一些很好的参考资料,用于理解方法,类型,并且接口可以在Go中互相工作和集成:


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 to 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.

解决方案

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\n", f, f)
}

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:

这篇关于&QUOT;&LT;类型&GT;是指向接口的指针,而不是接口“混乱的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆