【问题标题】:Property in Golang struct not getting modifiedGolang 结构中的属性没有被修改
【发布时间】:2017-10-03 03:15:31
【问题描述】:

我来自 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 类型系统的一些内容。

【问题讨论】:

  • FWIW String() 通常是实现fmt.Stringer (golang.org/pkg/fmt/#Stringer) 接口的方法String() string。大多数 Go 程序员会惊讶地看到 String() 不返回 string

标签: go


【解决方案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()
}

【讨论】:

    【解决方案2】:

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

     func (g *Graph) addNode(node *Node) {
        g.nodes = append(g.nodes, node)
     }
    
     ...
     n1 := Node { name: "abc", }
     graph.addNode(&n1)
     ...
     n1.addEdge(&n2)
    

    【讨论】:

      猜你喜欢
      • 2013-03-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-05-29
      • 2018-10-21
      • 2020-11-18
      相关资源
      最近更新 更多