在 Golang 中,循环内部追加操作会重复最后一个值。

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

Appending inside a loop repeats the last value in Golang

问题

在尝试将迭代的值附加到Go中时,该函数会将最后一个迭代附加四次。例如,我试图将包含网络卡数据的字符串解析为映射,但在迭代时只附加最后一个:

以下是包含代码的playground链接:
https://go.dev/play/p/mKtFvK36PMn

  1. package main
  2. import (
  3. "fmt"
  4. "strings"
  5. )
  6. type Foo struct {
  7. val int
  8. }
  9. func main() {
  10. NetworkJson := "4 NIC(s) Installed.,[01]: Realtek PCIe GbE Family Controller, Connection Name: Ethernet, DHCP Enabled: Yes, DHCP Server: 10.101.10.13, IP address(es), [01]: 10.1.2.62,[02]: VirtualBox Host-Only Ethernet Adapter, Connection Name: VirtualBox Host-Only Network, DHCP Enabled: No, IP address(es), [01]: 192.168.56.1, [02]: fe80::4c17:978a:2c91:8e27,[03]: VMware Virtual Ethernet Adapter for VMnet1, Connection Name: VMware Network Adapter VMnet1, DHCP Enabled: Yes, DHCP Server: 192.168.146.254, IP address(es), [01]: 192.168.146.1, [02]: fe80::88b4:d443:2ab8:59b5,[04]: VMware Virtual Ethernet Adapter for VMnet8, Connection Name: VMware Network Adapter VMnet8, DHCP Enabled: Yes, DHCP Server: 192.168.128.254, IP address(es), [01]: 192.168.128.1, [02]: fe80::a40d:e64:fa9f:e82f"
  11. var IPs []string
  12. var Data []string
  13. var IPMap = make(map[string]string)
  14. var CardMap = make(map[string]interface{})
  15. var CardIP = make(map[string][]map[string]string)
  16. var NetCard = make(map[string][]interface{})
  17. // Loop through network cards
  18. for _, Cards := range strings.Split(string(NetworkJson), ",[") {
  19. // Loop through data of each card
  20. for _, CardData := range strings.Split(string(Cards), ",") {
  21. // Check if data starts with whitespace
  22. if strings.HasPrefix(CardData, " ") {
  23. // Check if data without whitespace starts with [
  24. if strings.HasPrefix(strings.TrimSpace(CardData), "[") {
  25. // Get IPs
  26. IPs = strings.Split(strings.TrimSpace(string(CardData)), ": ")
  27. IPMap[string(IPs[0])] = strings.TrimSpace(string(IPs[1]))
  28. // If it doesn't start with [, check if it contains :
  29. } else if strings.Contains(CardData, ":") {
  30. // Get remaining data
  31. Data = strings.Split(strings.TrimSpace(string(CardData)), ":")
  32. CardMap[Data[0]] = strings.TrimSpace(Data[1])
  33. }
  34. }
  35. }
  36. if strings.Contains(Cards, "]") {
  37. // Assign data
  38. CardMap["Card Name"] = string(strings.SplitN(string(Cards), ",", 2)[0])[5:]
  39. CardIP["IP Adress(es)"] = append(CardIP["IP Adress(es)"], IPMap)
  40. CardMap["IP Adress(es)"] = CardIP["IP Adress(es)"]
  41. CardIP["IP Adress(es)"] = CardIP["IP Adress(es)"][:0]
  42. NetCard["Cards"] = append(NetCard["Cards"], CardMap)
  43. fmt.Println(CardMap)
  44. }
  45. fmt.Println(NetCard["Cards"])
  46. }
  47. }
英文:

When trying to append the values of an iteration in go, the function is appending the last iteration 4 times. For example, i'm trying to parse a string containing network cards data into a map, and when iterating it only appends the last one:

Here's the playground link with the code:
https://go.dev/play/p/mKtFvK36PMn

  1. package main
  2. import (
  3. "fmt"
  4. "strings"
  5. )
  6. type Foo struct {
  7. val int
  8. }
  9. func main() {
  10. NetworkJson := "4 NIC(s) Installed.,[01]: Realtek PCIe GbE Family Controller, Connection Name: Ethernet, DHCP Enabled: Yes, DHCP Server: 10.101.10.13, IP address(es), [01]: 10.1.2.62,[02]: VirtualBox Host-Only Ethernet Adapter, Connection Name: VirtualBox Host-Only Network, DHCP Enabled: No, IP address(es), [01]: 192.168.56.1, [02]: fe80::4c17:978a:2c91:8e27,[03]: VMware Virtual Ethernet Adapter for VMnet1, Connection Name: VMware Network Adapter VMnet1, DHCP Enabled: Yes, DHCP Server: 192.168.146.254, IP address(es), [01]: 192.168.146.1, [02]: fe80::88b4:d443:2ab8:59b5,[04]: VMware Virtual Ethernet Adapter for VMnet8, Connection Name: VMware Network Adapter VMnet8, DHCP Enabled: Yes, DHCP Server: 192.168.128.254, IP address(es), [01]: 192.168.128.1, [02]: fe80::a40d:e64:fa9f:e82f"
  11. var IPs []string
  12. var Data []string
  13. var IPMap = make(map[string]string)
  14. var CardMap = make(map[string]interface{})
  15. var CardIP = make(map[string][]map[string]string)
  16. var NetCard = make(map[string][]interface{})
  17. // Faz loop entre as placas de rede
  18. for _, Cards := range strings.Split(string(NetworkJson), ",[") {
  19. // Faz loop entre os dados de cada placa
  20. for _, CardData := range strings.Split(string(Cards), ",") {
  21. // Verifica se dado inicia com espaço em branco
  22. if strings.HasPrefix(CardData, " ") {
  23. // Verifica se dado sem o espaço em branco começa com [
  24. if strings.HasPrefix(strings.TrimSpace(CardData), "[") {
  25. // Pega IPS
  26. IPs = strings.Split(strings.TrimSpace(string(CardData)), ": ")
  27. IPMap[string(IPs[0])] = strings.TrimSpace(string(IPs[1]))
  28. // Se não iniciar com [ verifica se contém :
  29. } else if strings.Contains(CardData, ":") {
  30. // Pega restante dos dados
  31. Data = strings.Split(strings.TrimSpace(string(CardData)), ":")
  32. CardMap[Data[0]] = strings.TrimSpace(Data[1])
  33. }
  34. }
  35. }
  36. if strings.Contains(Cards, "]") {
  37. // Aloca dados
  38. CardMap["Card Name"] = string(strings.SplitN(string(Cards), ",", 2)[0])[5:]
  39. CardIP["IP Adress(es)"] = append(CardIP["IP Adress(es)"], IPMap)
  40. CardMap["IP Adress(es)"] = CardIP["IP Adress(es)"]
  41. CardIP["IP Adress(es)"] = CardIP["IP Adress(es)"][:0]
  42. NetCard["Cards"] = append(NetCard["Cards"], CardMap)
  43. fmt.Println(CardMap)
  44. }
  45. fmt.Println(NetCard["Cards"])
  46. }
  47. }

答案1

得分: 1

你将所有内容都存储在同一个名为CardMap的映射变量中,并且使用了一个名为"Card Name"的单一键。append(NetCard["Cards"], CardMap)并没有对CardMap进行深拷贝,只是追加了一个浅拷贝,因此浅拷贝的数据在每次迭代时都被更新。你的其他变量也有同样的问题。

将变量声明移到主循环中:

  1. var NetCard = make(map[string][]interface{})
  2. // Faz loop entre as placas de rede
  3. for _, Cards := range strings.Split(string(NetworkJson), ",[") {
  4. var IPs []string
  5. var Data []string
  6. var IPMap = make(map[string]string)
  7. var CardMap = make(map[string]interface{})
  8. var CardIP = make(map[string][]map[string]string)
  9. // Faz loop entre os dados de cada placa
  10. for _, CardData := range strings.Split(string(Cards), ",") {
  11. // ...

https://go.dev/play/p/VE_VWOsvsna

英文:

You are storing everything into the same map variable CardMap and you are using a singular key "Card Name". The append(NetCard["Cards"], CardMap) does not do a deep copy of the CardMap, only a shallow copy is appended and therefore the shallow copy's data is being update on every iteration. Your other variables have the same problem.

Move the variable declaration into the main loop:

  1. var NetCard = make(map[string][]interface{})
  2. // Faz loop entre as placas de rede
  3. for _, Cards := range strings.Split(string(NetworkJson), ",[") {
  4. var IPs []string
  5. var Data []string
  6. var IPMap = make(map[string]string)
  7. var CardMap = make(map[string]interface{})
  8. var CardIP = make(map[string][]map[string]string)
  9. // Faz loop entre os dados de cada placa
  10. for _, CardData := range strings.Split(string(Cards), ",") {
  11. // ...

https://go.dev/play/p/VE_VWOsvsna

huangapple
  • 本文由 发表于 2022年3月11日 19:07:21
  • 转载请务必保留本文链接:https://go.coder-hub.com/71437577.html
匿名

发表评论

匿名网友

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

确定