我来自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的类型系统的信息。
这不是类型系统问题,而是Go中如何传递数据的问题。
我认为根本的误解是关于“通过引用”。在Go中,所有内容均按值传递,没有按引用传递(https://golang.org/doc/faq#pass_by_value)
因此,当您将一个Node结构传递给该addEdge方法时,它实际上是在复制该结构。
Node
addEdge
如果要引用相同的基础结构而不是复制它,则应将指针传递给它。
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() }