指针的切片,当传递给对象时,会得到具有其他地址的指针。

huangapple go评论174阅读模式
英文:

Slice of pointers, when passed to object, gets pointers with other addresses

问题

我正在尝试传递一个实现LogicAdapter接口的结构体指针切片。以下是我的代码:

main.go:

var adapters []LogicAdapter
adapter1 := &ExampleAdapter{}
fmt.Printf("Addr: %p\n", adapter1)
adapters = append(adapters, adapter1)
bot := ChatterBot{"Charlie", MultiLogicAdapter{adapters}}
bot.getResponse("test", 0)

multiadapterlogic.go:

type MultiLogicAdapter struct {
    adapters []LogicAdapter
}

func (logic *MultiLogicAdapter) process(text string, session int) string {
    //response := logic.adapters[0].process(text, session)
    response := ""
    for _, adapter := range logic.adapters {
        fmt.Printf("Addr: %p\n", &adapter)
    }
    _ = response
    return ""
}

main函数的输出结果是:

Addr: 0x5178f0

Addr: 0xc42000a340

我没有包含LogicAdapter的代码,因为我认为这不是必要的。我不喜欢在这里填充太多代码,但是如果有助于理解的话,这是ChatterBot的代码(请记住,bot.getResponse调用process,仅此而已)

chatterbot.go:

type ChatterBot struct {
    Name string
    MultiLogicAdapter
}

func (bot *ChatterBot) getResponse(text string, session int) string {
    response := bot.process(text, session)
    _ = response
    return ""
}

首先,我想到了将LogicAdapter的指针存储在这种方式中:

var adapters []*LogicAdapter

但是每次我尝试将adapter1指针插入其中时,我都会得到:

*LogicAdapter是指向接口的指针,而不是接口

所以我发现了这个并学到了这个:

> 当你有一个实现接口的结构体时,指向该结构体的指针也会自动实现该接口。这就是为什么在函数的原型中从不使用*SomeInterface,因为这对SomeInterface没有任何增加,并且在变量声明中不需要这样的类型(请参阅这个相关问题)。

所以我决定像你在代码中看到的那样保留adapters[]声明。问题是,除了adapters存储了指向adapter1的指针之外,在MultiLogicAdapter中打印出来的是另一个地址。我知道我将adapters作为副本传递给MultiLogicAdapter,但是副本应该具有对adapter1的相同引用。所发生了什么?

为什么我要迭代指针?因为这个:https://www.goinggo.net/2013/09/iterating-over-slices-in-go.html
如果我不这样做,我将创建许多不必要的副本。

英文:

I'm trying to pass a slice of pointers to structs that implement the interface LogicAdapter. Here's my code:

main.go:

var adapters[]LogicAdapter
    adapter1 := &ExampleAdapter{}
    fmt.Printf("Addr: %p\n", adapter1)
    adapters = append(adapters, adapter1)
    bot := ChatterBot{"Charlie", MultiLogicAdapter{adapters}}
    bot.getResponse("test", 0)

multiadapterlogic.go:

type MultiLogicAdapter struct {
    adapters []LogicAdapter
}

func (logic *MultiLogicAdapter) process(text string, session int) string {
    //response := logic.adapters[0].process(text, session)
    response := ""
    for _, adapter := range logic.adapters {
        fmt.Printf("Addr: %p\n", &adapter)
    }
    _ = response
    return ""
}

The output of main is:

Addr: 0x5178f0

Addr: 0xc42000a340

I didn't include LogicAdapter because I don't think it's necessary.
I don't like to fill this with much code, but here's ChatterBot if it makes things easier to understand (but keep in mind that bot.getResponse calls process, that's it)

chatterbot.go

type ChatterBot struct {
    Name string
    MultiLogicAdapter
}

func (bot *ChatterBot) getResponse(text string, session int) string {
    response := bot.process(text, session)
    _ = response
    return ""
}

First of all, I had the idea of storing pointers to LogicAdapters, in this way

var adapters[]*LogicAdapter

but everytime I tried to insert the adapter1 pointer there, I got:

*LogicAdapter is pointer to interface, not interface

so I discovered this and learned this:

> When you have a struct implementing an interface, a pointer to that
> struct implements automatically that interface too. That's why you
> never have *SomeInterface in the prototype of functions, as this
> wouldn't add anything to SomeInterface, and you don't need such a type
> in variable declaration (see this related question).

So I decided to leave the adapters[] declaration as you see in the code. The problem is that besides adapters storing a pointer to adapter1, when it gets printed in MultiLogicAdapter, it's another address. I know that I'm passing adapters to MultiLogicAdapter as a copy, but the copy would have the same references to adapter1. So what's happening?

Why I'm iterating through pointers? Because of this: https://www.goinggo.net/2013/09/iterating-over-slices-in-go.html
If I don't, I'll be creating lots of unecessary copies.

答案1

得分: 0

var adapters []LogicAdapter中,你有一个接口数组。接口本身实质上是一个对象,它携带了指向你分配给它的对象的指针(还有一些额外的信息来跟踪其类型等)。因此,当你将*ExampleAdapter附加到它时,你将创建一个接口实例,该实例持有指向ExampleAdapter的指针。

稍后,当你执行for _, adapter := range logic.adapters {...}时,循环中声明的变量adapter将是切片中接口“对象”的副本。因此,当你使用&adapter获取它的指针时,你得到的是指向_接口_的指针,而不是接口中包含的指向ExampleAdapter的指针。

有关接口内部的更详细的解释,请参见例如https://research.swtch.com/interfaces。

英文:

In var adapters []LogicAdapter, you have an array of interfaces. The interface is itself essentially an object carrying a pointer to the object you assigned to it (with some extra information to track its type etc.). So when you append an *ExampleAdapter to it, you will create an interface instance holding a pointer to an ExampleAdapter.

Later, when you do for _, adapter := range logic.adapters {...}, the variable adapter declared in the loop will be a copy of the interface "object" in the slice. So when you take a pointer to it with &adapter you get a pointer to the interface, not to the ExampleAdapter the interface contains a pointer to.

For a more detailed exposition of the internals of interfaces, see for example https://research.swtch.com/interfaces.

huangapple
  • 本文由 发表于 2017年2月5日 16:13:35
  • 转载请务必保留本文链接:https://go.coder-hub.com/42049875.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定