Golang结构中的属性未被修改

时间:2017-10-03 03:15:32

标签: go

我来自Java并试图弄清楚Go的类型系统是如何工作的。我想创建一个简单的图形数据结构并实现广度优先搜索。这是我到目前为止所做的。

package graph

import "fmt"

type Node struct {
    neighbors []Edge
    visited   bool
    name      string
}

type Edge struct {
    neighbor Node
}

type Graph struct {
    nodes []Node
}

func (g *Graph) addNode(node Node) {
    g.nodes = append(g.nodes, node)
}

func (n *Node) addEdge(neighbor Node) {
    edge := Edge{
        neighbor: neighbor,
    }
    n.neighbors = append(n.neighbors, edge)
}

func (g Graph) String() {
    for _, node := range g.nodes {
        //fmt.Printf("nodename: %v", node.name)
        fmt.Println(len(node.neighbors))
        if len(node.neighbors) > 0 {
            fmt.Print("node: %v, edges: ", node.name)
            for _, e := range node.neighbors {
                fmt.Print(e.neighbor.name)
            }
        }
    }
}

当我尝试使用测试代码运行它时:

func TestGraph(t *testing.T) {
    graph := Graph{}
    n1 := Node { name: "abc", }
    n2 := Node { name: "def", }
    graph.addNode(n1) 
    graph.addNode(n2) 
    n1.addEdge(n2)

    graph.String()
}

在我的String()方法中,len(node.neighbors)总是为0.我做错了什么?我认为,因为我在addEdge中引用了一个引用类型,它修改了节点引用,但我显然错过了Go的类型系统。

2 个答案:

答案 0 :(得分:3)

这不是类型系统问题,而是Go中如何传递数据的问题。

我认为根本误解是关于"通过引用传递"。在Go中,所有内容都按值传递,没有通过引用传递(https://golang.org/doc/faq#pass_by_value

因此,当您将Node结构传递给addEdge方法时,它实际上正在制作该结构的副本。

如果你想引用相同的底层结构而不是复制它,你应该将指针传递给它。

尝试使用以下略微修改的代码,它使用指针传递结构:(您可以在此处调整并运行代码:https://play.golang.org/p/Qsbi4LBXS4

package main

import "fmt"

type Node struct {
    neighbors []*Edge
    visited   bool
    name      string
}

type Edge struct {
    neighbor *Node
}

type Graph struct {
    nodes []*Node
}

func (g *Graph) addNode(node *Node) {
    g.nodes = append(g.nodes, node)
}

func (n *Node) addEdge(neighbor *Node) {
    edge := &Edge{
        neighbor: neighbor,
    }
    n.neighbors = append(n.neighbors, edge)
}

func (g Graph) String() {
    for _, node := range g.nodes {
        //fmt.Printf("nodename: %v", node.name)
        fmt.Printf("number of neighbors: %d\n", len(node.neighbors))
        if len(node.neighbors) > 0 {
            fmt.Printf("node: %v, edges: ", node.name)
            for _, e := range node.neighbors {
                fmt.Printf("%q", e.neighbor.name)
            }
            fmt.Println()
        }
    }
}

func main() {
    graph := &Graph{}
    n1 := &Node{name: "abc"}
    n2 := &Node{name: "def"}
    graph.addNode(n1)
    graph.addNode(n2)
    n1.addEdge(n2)

    graph.String()
}

答案 1 :(得分:1)

您需要通过指针传递变量或创建新值

 func (g *Graph) addNode(node *Node) {
    g.nodes = append(g.nodes, node)
 }

 ...
 n1 := Node { name: "abc", }
 graph.addNode(&n1)
 ...
 n1.addEdge(&n2)