Golang结构体中Slice无法追加新值,仅保留初始值问题
问题分析与解决方案
核心问题:遍历切片时操作的是值副本
你在遍历usersQuotes时使用了for _, userQuote := range usersQuotes,这里的userQuote是切片对应元素的值副本,并非原切片中结构体的引用。当执行userQuote.QuoteNumbers = append(userQuote.QuoteNumbers, quote)时,只是修改了这个临时副本的切片,原切片usersQuotes里的元素完全不受影响,所以后续看不到追加的quote。
次要问题:随机数种子重复初始化
把rand.Seed(time.Now().UnixNano())放在循环内部,会导致每次循环都重置随机数生成器。由于循环执行速度极快,time.Now().UnixNano()可能返回相同值,最终生成的随机数会大量重复,导致quote分配完全不均匀。
修复后的代码
type UserQuote struct { User models.User QuoteNumbers []int } usersQuotes := make([]UserQuote, 0) if len(usersThatBuySweepstakeNumbersBySweepstake) == 0 { // 补充空用户列表的处理逻辑 } availableQuotes := GetAvailableSweepStakesNumbersNumbers(sweepStake.ID) if availableQuotes == nil || len(availableQuotes) == 0 { c.AbortWithStatusJSON(400, gin.H{ "message": "Não há mais números disponíveis para este sorteio", }) return // 提前返回,避免后续无效代码执行 } // 将随机数种子初始化移到循环外,仅执行一次 rand.Seed(time.Now().UnixNano()) for _, quote := range availableQuotes { randomIndex := rand.Intn(len(usersThatBuySweepstakeNumbersBySweepstake)) selectedUser := usersThatBuySweepstakeNumbersBySweepstake[randomIndex] selectedUserIsInList := false // 通过索引访问原切片元素,直接修改原结构体 for i := range usersQuotes { if usersQuotes[i].User.ID == selectedUser.ID { usersQuotes[i].QuoteNumbers = append(usersQuotes[i].QuoteNumbers, quote) selectedUserIsInList = true break // 找到匹配用户后立即跳出循环,减少不必要遍历 } } if !selectedUserIsInList { usersQuotes = append(usersQuotes, UserQuote{ User: selectedUser, QuoteNumbers: []int{quote}, }) } }
额外优化建议
如果用户数量较多,用切片遍历查找的效率会很低(时间复杂度O(n)),可以改用map存储用户与quote的关联,以用户ID为键,将查找操作的时间复杂度降到O(1):
// 用map替代切片,key为用户ID(根据实际类型调整键的类型) userQuoteMap := make(map[uint]UserQuote) // 分配quote的逻辑修改为: for _, quote := range availableQuotes { randomIndex := rand.Intn(len(usersThatBuySweepstakeNumbersBySweepstake)) selectedUser := usersThatBuySweepstakeNumbersBySweepstake[randomIndex] if uq, exists := userQuoteMap[selectedUser.ID]; exists { uq.QuoteNumbers = append(uq.QuoteNumbers, quote) userQuoteMap[selectedUser.ID] = uq } else { userQuoteMap[selectedUser.ID] = UserQuote{ User: selectedUser, QuoteNumbers: []int{quote}, } } } // 若后续需要转回切片,遍历map即可: var usersQuotes []UserQuote for _, uq := range userQuoteMap { usersQuotes = append(usersQuotes, uq) }
内容的提问来源于stack exchange,提问作者João Vitor Oliveira Corrêa
相关产品推荐
相关产品推荐

