Pointers &引用&书信电报;类型>;是指向接口的指针,而不是“接口”;混乱

Pointers &引用&书信电报;类型>;是指向接口的指针,而不是“接口”;混乱,pointers,go,interface,Pointers,Go,Interface,我有个问题,我觉得有点奇怪。请看这段代码: 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 FilterMap

我有个问题,我觉得有点奇怪。请看这段代码:

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
}
在其他一些软件包中,我有以下代码:

func DoFilter() {
    fieldfilter := &coreinterfaces.FieldFilter{Key: "app", Val: "152511"}
    filtermap := &coreinterfaces.FilterMap{}
    _ = filtermap.AddFilter(fieldfilter) // <--- Exception is raised here
}
一切正常,在调试应用程序时,它似乎真的包括了

我对这个话题有点困惑。当看到其他博客文章和堆栈溢出线程讨论这个完全相同的问题时(例如-,或
)引发此异常的第一个代码段应该可以工作,因为fieldfilter和fieldmap都初始化为指向接口的指针,而不是接口的值。我还不能完全理解这里到底发生了什么,为了不声明FieldInterface并为该接口分配实现,我需要对其进行更改。一定有一种优雅的方法可以做到这一点。

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

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)
}
输出:

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

在这两种情况下,
DoFoo
中的
f
变量只是一个接口,而不是指向接口的指针。但是,当存储
f2
时,接口会保存指向
Foo
结构的指针

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


但是,接口有一个限制。如果将结构直接传递给接口,则只能使用该类型的值方法(即
func(f Foo)Dummy()
,而不是
func(f*Foo)Dummy()
)来实现接口。这是因为您正在接口中存储原始结构的副本,因此指针方法将产生意外的效果(即无法更改原始结构)。因此,默认的经验法则是在接口中存储指向结构的指针,除非有令人信服的理由不这样做

如果将AddFilter函数签名更改为:

func (fp *FilterMap) AddFilter(f FilterInterface) uuid.UUID
func (fp *FilterMap) GetFilterByID(i uuid.UUID) FilterInterface
并将GetFilterByID签名发送到:

func (fp *FilterMap) AddFilter(f FilterInterface) uuid.UUID
func (fp *FilterMap) GetFilterByID(i uuid.UUID) FilterInterface
您的代码将按预期工作
fieldfilter
属于
*fieldfilter
类型,它填充了
FilterInterface
接口类型,因此
AddFilter
将接受它

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

当我遇到这个错误时,通常是因为我指定了一个指向接口的指针,而不是接口(实际上是指向实现接口的结构的指针)

*接口{…}有一个有效的用法,但更常见的是,我只是想“这是一个指针”,而不是“这是一个接口,它恰好是我正在编写的代码中的指针”


只是把它扔出去,因为被接受的答案虽然很详细,但并没有帮助我解决问题。

当将
*FilterInterface
更改为
FilterInterface
时,
\uu=filtermap.AddFilter(fieldfilter)
这一行现在引发了这样的问题:不能使用fieldfilter(键入coreeterfaces.fieldfilter)作为filtermap.AddFilter的参数中的coreinterfaces.FilterInterface类型:coreinterfaces.FieldFilter不实现coreinterfaces.FilterInterface(Filter方法具有指针接收器),但是当将行更改为
\uU9=filtermap.AddFilter(&FieldFilter)
时,它可以工作。这里发生了什么?为什么会这样?因为实现接口的方法都有指针接收器。传递一个值,它不实现接口;它会传递一个指针,因为方法随后会应用。一般来说,在处理接口时,将指向结构的指针传递给需要接口的函数。在任何情况下,您几乎都不需要指向接口的指针。我理解您的观点,但通过将参数值从
*FilterInterface
更改为实现此接口的结构,这打破了将接口传递给函数的想法。我想要完成的不是绑定到我要传递的结构,而是实现我感兴趣的接口的任何结构。您认为有哪些代码更改更有效或更符合我的标准?我很乐意使用一些代码审查服务:)您的函数应该接受接口参数(而不是指向接口的指针)。调用方应传入指向实现接口的结构的指针。这并没有“打破将接口传递给函数的想法”-函数仍然接受一个接口,您正在传递实现接口的具体化。“这是因为您在接口中存储原始结构的副本,因此指针方法将产生意外的效果(即无法更改原始结构)”-作为限制的原因,这没有意义。毕竟,唯一的副本可能一直存储在界面中。你的答案毫无意义。您假设当您更改存储在接口中的内容时,接口中存储具体类型的位置不会更改,但事实并非如此,如果您使用不同的内存布局存储某些内容,这一点应该是显而易见的。关于我的指针注释,您没有得到的是,具体类型上的指针接收器方法始终可以修改它所调用的接收器。存储在接口中的值强制创建一个副本,而您随后无法获取对该副本的引用,因此指针接收器无法修改原始副本