golang数组问题,想了一个上午没发现问题出在哪,求大神帮忙解答一下

这是我的一段代码,我把数组 []Node 作为一个参数传递给Init函数,希望将其保存在Server结构体里的nodes数组中。

package main

import (
    "fmt"
)

type Node struct {
    id  string
    ipaddr string
}

type Server struct {
    nodes [5]*Node
    num int
}

func (s *Server)Init(n int, nodes []Node) {
    s.num = n
    for idx,v := range nodes {
        s.nodes[idx] = &v
    }
}

func (s *Server)Print() {
    for idx,v := range s.nodes {
        if(v!=nil) {
            fmt.Printf("%d) %s--%s\n", idx, v.id, v.ipaddr)
        }   
    }
}

func main() {
    nodes := []Node {
        Node{"0", "192.168.0.0.0"},
        Node{"1", "192.168.0.0.1"},
        Node{"2", "192.168.0.0.2"},
    }

    var s Server
    s.Init(3, nodes)
    s.Print()
}

期望输出:

0) 0--192.168.0.0.0
1) 1--192.168.0.0.1
2) 2--192.168.0.0.2

实际输出:

0) 2--192.168.0.0.2
1) 2--192.168.0.0.2
2) 2--192.168.0.0.2

数组中的前几个元素都被最后一个添加的元素给覆盖了。不知道什么原因。 大神们能帮我看一下问题出在哪么,出错的具体原因在哪

已邀请:

wshlovercn

赞同来自: xiaoma moyuanhui

这个问题,实际上可以分两个方面去考虑。 1,作者的设计思路是什么 2,golang 的值变量,指针变量的理解。

1,设计意图不清晰。为什么初始化的时候,以及函数传值的时候,采用值变量切片。然而,在Server 结构里面,使用的是一个5 个元素的数组?并且数组的成员是指针?那么,Server 结构里面的Node 与 最初初始化的Node,是想使用共享变量?还是希望相互独立?搞清楚这些目的之后,我们来考虑修改方案。

2.1,如果希望使用共享Node,建议的修改方式是,直接修改Server 的数据成员为 []Node,直接切片赋值就好了,没必要循环赋值。

2.2,如果希望Server 中的nodes 自成一套,那么统一Node 已值变量方式使用。也就该Server 的nodes 成员为 []Node,使用循环赋值就可以。

3,在涉及到变量的传参,引用(成员变量)等操作时,最好根据数据本身的性质。确定好使用统一的方式:使用值变量,还是指针变量,不必要的情况下,尽量避免混用。

4,最后,楼主对go语言的值变量,指针变量,数组,切片,函数传参,循环变量生命周期等,感觉使用比较随意,可能是理解不够吧。

jkkkls

赞同来自: littlebeast0

v的值三次循环被覆盖3次啊,最后一次就是最后一个元素@littlebeast0:

programmersky

赞同来自:

package main

import (
    "fmt"
)

type Node struct {
    id     string
    ipaddr string
}

type Server struct {
    nodes [5]*Node
    num   int
}

func (s *Server) Init(n int, nodes []*Node) {
    s.num = n
    for idx, _ := range nodes {
        s.nodes[idx] = nodes[idx]
    }
}

func (s *Server) Print() {
    for idx, v := range s.nodes {
        if v != nil {
            fmt.Printf("%d) %s--%s\n", idx, v.id, v.ipaddr)
        }
    }
}

func main() {
    nodes := []*Node{
        &Node{"0", "192.168.0.0.0"},
        &Node{"1", "192.168.0.0.1"},
        &Node{"2", "192.168.0.0.2"},
    }

    var s Server
    s.Init(3, nodes)
    s.Print()
}

heramerom

赞同来自:

func (s *Server)Init(n int, nodes []Node) {
    s.num = n
    for idx := range nodes {
        s.nodes[idx] = &nodes[idx]
    }
}

jkkkls

赞同来自:

这里的v是一个临时变量,for里重复使用的

for idx,v := range s.nodes {
}

改成这样

nodes := []*Node {
        &Node{"0", "192.168.0.0.0"},
        &Node{"1", "192.168.0.0.1"},
        &Node{"2", "192.168.0.0.2"},
    }

Xibbb

赞同来自:

for i, v := range nodes { }

这里的v的值是数组item的拷贝,然后 这里又把v的指针传进去了s.nodes[idx] = &v,最后一次&v值是2--192.168.0.0.2,所有s.nodes 里所有的 &v 都是这个值

改成这样就好了:

package main

import (
    "fmt"
)

type Node struct {
    id  string
    ipaddr string
}

type Server struct {
    nodes [5]*Node
    num int
}

func (s *Server)Init(n int, nodes []*Node) {
    s.num = n
    for idx,v := range nodes {
        s.nodes[idx] = v
    }
}

func (s *Server)Print() {
    for idx,v := range s.nodes {
        if(v!=nil) {
            fmt.Printf("%d) %s--%s\n", idx, v.id, v.ipaddr)
        }
    }
}

func main() {
    nodes := []*Node {
        &Node{"0", "192.168.0.0.0"},
        &Node{"1", "192.168.0.0.1"},
        &Node{"2", "192.168.0.0.2"},
    }

    var s Server
    s.Init(3, nodes)
    s.Print()
}

xiaoma

赞同来自:

加个变量就好了

for idx,v := range nodes {

    v:=v//此处加上即可
    s.nodes[idx] = &v
}

我甚至认为,在所有for下面都这么加一下,可以杜绝这个坑。

fwhezfwhez

赞同来自:

for i,v:=range arr 的结构里,v在迭代里是公用一个指针,换句话说,三次赋值,赋的都是arr最后一个node

Hawken - 已经毕业4个月了

赞同来自:

经典的 for range 问题

要回复问题请先登录注册