英文:
Golang changing values of a struct inside a method of another struct
问题
我有一个关于结构体的问题,也可能与指针有关,如果我猜得没错的话。
这个结构体有一些字段,还有一个保存切片的字段:
type Bot struct {
// ...
connlist []Connection
}
Connection
的定义如下:
type Connection struct {
conn net.Conn
messages int32
channels []string
joins int32
connactive bool
}
我的问题是将 connactive
的值改为 true
。
Bot
有一个监听连接的方法:
func (bot *Bot) ListenToConnection(connection Connection) {
reader := bufio.NewReader(connection.conn)
tp := textproto.NewReader(reader)
for {
line, err := tp.ReadLine()
if err != nil {
log.Printf("Error reading from chat connection: %s", err)
break // 在出现错误时跳出循环
}
if strings.Contains(line, "tmi.twitch.tv 001") {
connection.activateConn()
}
if strings.Contains(line, "PING ") {
fmt.Fprintf(connection.conn, "PONG tmi.twitch.tv\r\n")
}
fmt.Fprintf(bot.inconn, line+"\r\n")
}
}
而 connection.activateConn()
是出现问题的部分,该方法的定义如下:
func (connection *Connection) activateConn() {
connection.connactive = true
}
这部分实际上是被执行的,所以不是连接没有得到响应之类的问题。
但是,如果我稍后在 Bot
的一个方法中尝试循环遍历它,connactive
总是为 false
(默认值)。
for i := 0; i < len(bot.connlist); i++ {
log.Println(bot.connlist[i].connactive)
}
我认为我是在使用原始连接的副本,而不是已经更改为 connactive = true
的连接。
有什么想法吗?谢谢帮助。
英文:
I have an issue with structs and maybe an issue with pointers, if my guess is correct.
This struct has some fields and a field that holds a slice:
type Bot struct {
// ...
connlist []Connection
}
This Connection
looks like this:
type Connection struct {
conn net.Conn
messages int32
channels []string
joins int32
connactive bool
}
My problem is changing the value of connactive
to true
.
Bot
has a method that listens to the connection:
func (bot *Bot) ListenToConnection(connection Connection) {
reader := bufio.NewReader(connection.conn)
tp := textproto.NewReader(reader)
for {
line, err := tp.ReadLine()
if err != nil {
log.Printf("Error reading from chat connection: %s", err)
break // break loop on errors
}
if strings.Contains(line, "tmi.twitch.tv 001") {
connection.activateConn()
}
if strings.Contains(line, "PING ") {
fmt.Fprintf(connection.conn, "PONG tmi.twitch.tv\r\n")
}
fmt.Fprintf(bot.inconn, line+"\r\n")
}
}
And connection.activeConn()
is the part that is not working correctly the method looks like this:
func (connection *Connection) activateConn() {
connection.connactive = true
}
This actually gets executed so it's not an issue of the connection not getting a response or something.
But if I try to loop through it later in a method of Bot
, connactive
is always false
for some reason (which is the default).
for i := 0; i < len(bot.connlist); i++ {
log.Println(bot.connlist[i].connactive)
}
I think I am working with a copy or so of the original connection and not the changed connection that has connactive = true
.
Any ideas? Thanks for the help.
答案1
得分: 10
你的ListenToConnection()
方法有一个参数:connection Connection
。
当你调用这个ListenToConnection()
方法(你没有发布这段代码)时,你传递了一个Connection
的值。在Go语言中,所有的东西都是按值传递的,所以会对传递的值进行复制。在ListenToConnection()
内部,你操作的是这个副本。你调用了它的activateConn()
方法,但是这个方法(它有一个指针接收器)将接收到这个副本的地址(一个局部变量)。
解决方法很简单,将ListenToConnection()
的参数改为指针:
func (bot *Bot) ListenToConnection(connection *Connection) {
// ...
}
使用Bot.connlist
中的一个值调用它:
bot.ListenToConnection(&bot.connlist[0])
使用conlist
中的每个元素进行调用的for
循环:
for i := range bot.connlist {
bot.ListenToConnection(&bot.conlist[i])
}
**注意!**我故意使用了一个只使用索引而不使用值的for ... range
。如果使用带有索引和值的for ... range
,或者只使用值,你会观察到相同的问题(connactive
仍然为false
):
for _, v := range bot.connlist {
bot.ListenToConnection(&v) // 错误!v也是一个副本
}
因为v
也只是一个副本,将它的地址传递给bot.ListenToConnection()
,那只会指向副本,而不是connlist
切片中的元素。
英文:
Your ListenToConnection()
method has one parameter: connection Connection
.
When you call this ListenToConnection()
method (you didn't post this code), you pass a value of Connection
. Everything in Go is passed by value, so a copy will be made of the passed value. Inside ListenToConnection()
you operate with this copy. You call its activateConn()
method, but that method (which has a pointer receiver) will receive the address of this copy (a local variable).
Solution is simple, change parameter of ListenToConnection()
to be a pointer:
func (bot *Bot) ListenToConnection(connection *Connection) {
// ...
}
Calling it with a value from Bot.connlist
:
bot.ListenToConnection(&bot.connlist[0])
A for
loop calling it with every elements of conlist
:
for i := range bot.connlist {
bot.ListenToConnection(&bot.conlist[i])
}
Attention! I intentionally used a for ... range
which only uses the index and not the value. Using a for ... range
with index and value, or just the value, you would observe the same issue (connactive
would remain false
):
for _, v := range bot.connlist {
bot.ListenToConnection(&v) // BAD! v is also a copy
}
Because v
is also just a copy, passing its address to bot.ListenToConnection()
, that would only point to the copy and not the element in the connlist
slice.
答案2
得分: 1
需要将以下内容翻译为中文:
需要将连接的切片更改为指向连接的指针。
如果同时更改此属性,则需要使用信号量。
type Bot struct {
// ...
conns []*Connection
}
func (bot *Bot) ListenToConnection(c *Connection) {
// 代码
}
type Connection struct {
conn net.Conn
messages int32
channels []string
joins int32
isActive bool
isActiveLock sync.RWMutex
}
func (c *Connection) activateConn() {
c.isActiveLock.Lock()
defer c.isActiveLock.Unlock()
c.isActive = true
}
英文:
It needs to be slice of pointers to connections.
And if this property will be changed concurrently, semaphore is necessary.
type Bot struct {
// ...
conns []*Connection
}
func (bot *Bot) ListenToConnection(c *Connection) {
// code
}
type Connection struct {
conn net.Conn
messages int32
channels []string
joins int32
isActive bool
isActiveLock sync.RWMutex
}
func (c *Connection) activateConn() {
c.isActiveLock.Lock()
defer c.isActiveLock.Unlock()
c.isActive = true
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论