在 for 循环结束后,数组似乎丢失了值。

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

Array seems to lose values after end of for loop

问题

我是一个初学者,不是一个好的程序员,但我想编写一个小程序,使用SNMP从交换机中转储MAC地址和接口名称的列表。我使用多个循环将SNMP值存储到结构体数组中(这里的代码是为了展示行为)。
在第一个循环中,我将端口VLAN ID和MAC地址存储到结构体数组中(var allTableArray [30]allTable)。在此循环结束时,我打印数组的内容以确保MAC地址在数组中。
但是当第二个循环开始时(用于注册桥接端口号),数组似乎为空(fmt.Printf("deux %x\n",allTableArray[i].macAddr)fmt.Printf("trois %s\n",allTableArray[i].ptVlan1id))。

我不明白为什么数组似乎为空。你有任何想法吗?

package main

import (
    "flag"
    "fmt"
    "os"
    "time"
    "strings"
    "github.com/soniah/gosnmp"
    "math/big"
)

type oidMacAddr struct {
    oid string
    macaddr string
}

type allTable struct {
    ptVlan1id string
    macAddr []byte
    brPortNb *big.Int
    ifIndex *big.Int
    ifName string
}

var macAddrTable [30]oidMacAddr

func main() {
    flag.Parse()

    if len(flag.Args()) < 1 {
        flag.Usage()
        os.Exit(1)
    }
    target := flag.Args()[0]
    showMacAddrTable(target)
}

func printValue(pdu gosnmp.SnmpPDU) error {
    fmt.Printf("%s = ", pdu.Name)

    switch pdu.Type {
    case gosnmp.OctetString:
        b := pdu.Value.([]byte)
        fmt.Printf("STRING: %x\n", b)
    default:
        fmt.Printf("TYPE %d: %d\n", pdu.Type, gosnmp.ToBigInt(pdu.Value))
    }
    return nil
}

func showMacAddrTable(target string) {
    var allTableArray [30]allTable
    ptVlan1Oid := ".1.3.6.1.2.1.17.4.3.1.1"
    brPortOid := ".1.3.6.1.2.1.17.4.3.1.2"
    brPortIfIndex := ".1.3.6.1.2.1.17.1.4.1.2"
    ifIndexIfName := ".1.3.6.1.2.1.31.1.1.1.1"
    community := "public"

    gosnmp.Default.Target = target
    gosnmp.Default.Community = community
    gosnmp.Default.Timeout = time.Duration(10 * time.Second)
    err := gosnmp.Default.Connect()
    if err != nil {
        fmt.Printf("Connect err: %v\n", err)
        os.Exit(1)
    }

    var essai []gosnmp.SnmpPDU
    essai, err = gosnmp.Default.BulkWalkAll(ptVlan1Oid)
    if err != nil {
        fmt.Printf("Walk Error: %v\n", err)
        os.Exit(1)
    }
    for i := 0; i < len(essai); i++ {
        s := strings.TrimPrefix(essai[i].Name, ".1.3.6.1.2.1.17.4.3.1.1")
        fmt.Printf("%s = ", s)
        fmt.Printf("%x\n", essai[i].Value.([]byte))
        bytes := essai[i].Value.([]byte)
        macAddrTable[i] = oidMacAddr{s, string(bytes)}
        allTableArray[i] = allTable{ptVlan1id: s, macAddr: bytes}
        if allTableArray[i].macAddr != nil {
            fmt.Printf("%x\n", allTableArray[i].macAddr)
        }
    }
    essai, err = gosnmp.Default.BulkWalkAll(brPortOid)
    if err != nil {
        fmt.Printf("Walk Error: %v\n", err)
        os.Exit(1)
    }
    for i := 0; i < len(essai); i++ {
        s := strings.TrimPrefix(essai[i].Name, ".1.3.6.1.2.1.17.4.3.1.2")
        fmt.Printf("%s = ", s)
        fmt.Printf("%d\n", essai[i].Value)
        for j := 0; j < len(allTableArray); j++ {
            if s == allTableArray[j].ptVlan1id {
                allTableArray[j] = allTable{brPortNb: gosnmp.ToBigInt(essai[i].Value)}
            }
        }
        fmt.Printf("deux %x\n", allTableArray[i].macAddr)
        fmt.Printf("trois %s\n", allTableArray[i].ptVlan1id)
    }
    os.Exit(1)
}
英文:

I'm a beginner at go (and not a good programmer) but I wanted to write a small program which would dump from a switch the list of mac addresses & interfaces name using snmp. I store the snmp values into an array of struct using multiple loops (the code here is to show the behavior).
During the first loop, I store Ports Vlan id & mac addresses into an array of struct (var allTableArray [30]allTable). At the end of this loop, I print the content of the array to be sure the mac addresses are in the array.
But when the second loop begins (to register bridge port number), the array seems empty (fmt.Printf(&quot;deux %x\n&quot;,allTableArray[i].macAddr) and fmt.Printf(&quot;trois %s\n&quot;,allTableArray[i].ptVlan1id)).

I don't understand why my array seems empty. Do you have any idea ?

package main
import (
&quot;flag&quot;
&quot;fmt&quot;
&quot;os&quot;
&quot;time&quot;
&quot;strings&quot;
&quot;github.com/soniah/gosnmp&quot;
&quot;math/big&quot;
)
type oidMacAddr struct {
oid string
macaddr string
}
type allTable struct {
ptVlan1id string
macAddr []byte
brPortNb *big.Int
ifIndex *big.Int
ifName string
}
var macAddrTable [30]oidMacAddr
func main() {
flag.Parse()
if len(flag.Args()) &lt; 1 {
flag.Usage()
os.Exit(1)
}
target := flag.Args()[0]
showMacAddrTable(target)
}
func printValue(pdu gosnmp.SnmpPDU) error {
fmt.Printf(&quot;%s = &quot;, pdu.Name)
//fmt.Println(reflect.TypeOf(pdu.Value.([]byte)))
switch pdu.Type {
case gosnmp.OctetString:
b := pdu.Value.([]byte)
fmt.Printf(&quot;STRING: %x\n&quot;, b)
default:
fmt.Printf(&quot;TYPE %d: %d\n&quot;, pdu.Type, gosnmp.ToBigInt(pdu.Value))
}
return nil
}
func showMacAddrTable(target string) () {
var allTableArray [30]allTable
ptVlan1Oid := &quot;.1.3.6.1.2.1.17.4.3.1.1&quot;
brPortOid := &quot;.1.3.6.1.2.1.17.4.3.1.2&quot;
brPortIfIndex := &quot;.1.3.6.1.2.1.17.1.4.1.2&quot;
ifIndexIfName := &quot;.1.3.6.1.2.1.31.1.1.1.1&quot;
community := &quot;public&quot;
gosnmp.Default.Target = target
gosnmp.Default.Community = community
gosnmp.Default.Timeout = time.Duration(10 * time.Second) // Timeout better suited to walking
err := gosnmp.Default.Connect()
if err != nil {
fmt.Printf(&quot;Connect err: %v\n&quot;, err)
os.Exit(1)
}
var essai []gosnmp.SnmpPDU
essai, err = gosnmp.Default.BulkWalkAll(ptVlan1Oid)
if err != nil {
fmt.Printf(&quot;Walk Error: %v\n&quot;, err)
os.Exit(1)
}
for i :=0 ; i &lt; len(essai); i++ {
s := strings.TrimPrefix(essai[i].Name, &quot;.1.3.6.1.2.1.17.4.3.1.1&quot;)
fmt.Printf(&quot;%s = &quot;, s)
fmt.Printf(&quot;%x\n&quot;, essai[i].Value.([]byte))
bytes := essai[i].Value.([]byte)
macAddrTable[i] = oidMacAddr {s, string(bytes)}
allTableArray[i] = allTable {ptVlan1id: s, macAddr: bytes}
if(allTableArray[i].macAddr != nil){
fmt.Printf(&quot;%x\n&quot;,allTableArray[i].macAddr)
}
}
essai, err = gosnmp.Default.BulkWalkAll(brPortOid)
if err != nil {
fmt.Printf(&quot;Walk Error: %v\n&quot;, err)
os.Exit(1)
}
for i:=0 ; i &lt; len(essai); i++ {
s := strings.TrimPrefix(essai[i].Name, &quot;.1.3.6.1.2.1.17.4.3.1.2&quot;)
fmt.Printf(&quot;%s = &quot;, s)
fmt.Printf(&quot;%d\n&quot;, essai[i].Value)
for j:=0 ; j &lt; len(allTableArray); j++ {
if (s == allTableArray[j].ptVlan1id) {
allTableArray[j] = allTable {brPortNb: gosnmp.ToBigInt(essai[i].Value) }
}
}
fmt.Printf(&quot;deux %x\n&quot;,allTableArray[i].macAddr)
fmt.Printf(&quot;trois %s\n&quot;,allTableArray[i].ptVlan1id)
}
os.Exit(1)
}

答案1

得分: 1

显然,这一行代码:

allTableArray[j] = allTable {brPortNb: gosnmp.ToBigInt(essai[i].Value) }

更新每个成员的allTable实例,其中除了brPortNb字段之外的所有字段都未定义,因此变为nil

如果你想要做的是更新每个成员的brPortNb字段,你可以通过访问该字段并将值赋给它来实现,而不是为每个成员分配一个新的allTable

allTableArray[j].brPortNb = gosnmp.ToBigInt(essai[i].Value)

此外,尝试简化你的循环,假设len(essai) == len(allTableArray)

for i, v := range essai {
s := strings.TrimPrefix(v.Name, ".1.3.6.1.2.1.17.4.3.1.1")
bytes := v.Value.([]byte)
macAddrTable[i] = oidMacAddr { s, string(bytes) }
allTableArray[i] = allTable { ptVlan1id: s, macAddr: bytes }
s = strings.TrimPrefix(v.Name, ".1.3.6.1.2.1.17.4.3.1.2")
if s == allTableArray[i].ptVlan1id {
allTableArray[i].brPortNb = gosnmp.ToBigInt(v.Value)
}
}

请注意,使用for i, v := range essai语法,你可以同时访问索引和值,而不必使用essai[i]来获取值。

现在你的两个循环可以合并为一个,而且没有嵌套循环,这样更容易理解。

我还建议你使用切片而不是数组,这样更灵活。

英文:

Apparently this line

allTableArray[j] = allTable {brPortNb: gosnmp.ToBigInt(essai[i].Value) }

Update each member with a new allTable instance, where every field other than brPortNb is not defined thus becomes nil.

If what you were trying to do is to update each member's brPortNb field, you could have done so by accessing the field and assign the value to it instead of assigning a new allTable to every member.

allTableArray[j].brPortNb = gosnmp.ToBigInt(essai[i].Value)

Also, try simplifying your loops like this, provided len(essai) == len(allTableArray):

for i, v := range essai {
s := strings.TrimPrefix(v.Name, &quot;.1.3.6.1.2.1.17.4.3.1.1&quot;)
bytes := v.Value.([]byte)
macAddrTable[i] = oidMacAddr { s, string(bytes) }
allTableArray[i] = allTable { ptVlan1id: s, macAddr: bytes }
s = strings.TrimPrefix(v.Name, &quot;.1.3.6.1.2.1.17.4.3.1.2&quot;)
if s == allTableArray[i].ptVlan1id {
allTableArray[i].brPortNb = gosnmp.ToBigInt(v.Value)
}
}

Notice that by using for i, v := range essai syntax, you have access to both the index and the value without having to use essai[i] for the value.

Now your two loops can become just one, plus no embedded loops which are really hard to make sense of.

I Also recommend you work with slice instead of array. It's more flexible that way.

huangapple
  • 本文由 发表于 2016年3月16日 19:34:25
  • 转载请务必保留本文链接:https://go.coder-hub.com/36034541.html
匿名

发表评论

匿名网友

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

确定