一尘不染

Golang结构中的属性未修改

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的类型系统的信息。


阅读 265

收藏
2020-07-02

共1个答案

一尘不染

这不是类型系统问题,而是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()
    }
2020-07-02