我来自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的类型系统。
答案 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)