英文:
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论