Golang中结构体变量未按预期递增的问题

Golang中结构体变量未按预期递增的问题 大家好, 我有以下Go代码:

package a
type A struct {
  ...
  x int
  ...
}
////
package B
...
x map[string]a.A
...
func GetValByKey(key string) (a.A, bool) {
  val, exist := x[key]
  return val, exist
}
////
package C
func abc(c *gin.Context) {
  ws, err := WsUpgrader.Upgrade(c.Writer, c.Request, nil)
  defer ws.Close() 
  ...
  val, ok := GetValByKey(key)
  val.x++
  ...
  go handleEvents()
  for {
    ...
  }
}

现在,当我使用相同的键调用端点时,x的值在两种情况下都是从0开始增加的。即: 第一次调用, x的值(++之前):= 0 x的值(++之后):= 1 第二次调用, x的值(++之前):= 0 x的值(++之后):= 1 但对于第二次调用,我希望它是: x的值(++之前):= 1 x的值(++之后):= 2 我无法弄清楚问题可能出在哪里。你能帮忙吗?


更多关于Golang中结构体变量未按预期递增的问题的实战教程也可以访问 https://www.itying.com/category-94-b0.html

3 回复

结构体不是按值拷贝的吗?所以每次你调用 GetValByKey(key) 时,它返回的都是该结构体的一个副本。

更多关于Golang中结构体变量未按预期递增的问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


你是否需要将映射的值改为指向值的指针?类似下面这样:

package main

import (
	"fmt"
	"os"
)

type a struct {
	x int
}

type mapStrToAPtr map[string]*a

func getPtrValByKey(key string, m mapStrToAPtr) (*a, bool) {
	val, exist := m[key]
	return val, exist
}

func main() {
	m := map[string]*a{
		"G4143":  {4143},
		"Emily":  {1234},
		"Angela": {4321},
	}
	for key, value := range m {
		fmt.Fprintf(os.Stdout, "%s -> %d\n", key, *value)
	}
	if p, ok := getPtrValByKey("G4143", m); ok {
		p.x++
	}
	for key, value := range m {
		fmt.Fprintf(os.Stdout, "%s -> %d\n", key, *value)
	}
}

问题在于你的代码中每次调用GetValByKey返回的是结构体的副本,而不是原始值。在Go中,map返回的是值的副本,对副本的修改不会影响map中存储的原始值。

以下是修复后的代码示例:

package a

type A struct {
    X int
}
package b

import "a"

var data = make(map[string]a.A)

func GetValByKey(key string) (a.A, bool) {
    val, exist := data[key]
    return val, exist
}

func UpdateValByKey(key string, val a.A) {
    data[key] = val
}
package c

import (
    "a"
    "b"
    "github.com/gin-gonic/gin"
)

func abc(c *gin.Context) {
    ws, err := WsUpgrader.Upgrade(c.Writer, c.Request, nil)
    if err != nil {
        return
    }
    defer ws.Close()
    
    key := "some_key"
    val, ok := b.GetValByKey(key)
    if !ok {
        val = a.A{X: 0}
    }
    
    val.X++
    b.UpdateValByKey(key, val)
    
    go handleEvents()
    for {
        // 处理逻辑
    }
}

或者,你可以使用指针来存储结构体,这样可以直接修改原始值:

package a

type A struct {
    X int
}
package b

import "a"

var data = make(map[string]*a.A)

func GetValByKey(key string) (*a.A, bool) {
    val, exist := data[key]
    return val, exist
}
package c

import (
    "a"
    "b"
    "github.com/gin-gonic/gin"
)

func abc(c *gin.Context) {
    ws, err := WsUpgrader.Upgrade(c.Writer, c.Request, nil)
    if err != nil {
        return
    }
    defer ws.Close()
    
    key := "some_key"
    val, ok := b.GetValByKey(key)
    if !ok {
        val = &a.A{X: 0}
        b.data[key] = val
    }
    
    val.X++
    
    go handleEvents()
    for {
        // 处理逻辑
    }
}

在第二个方案中,由于map存储的是指针,对val.X的修改会直接反映到map中的原始值上。注意,使用指针时需要确保并发安全,可以考虑使用sync.RWMutex来保护map的访问。

回到顶部