戈朗 : Preferred way to tag a struct with aribtrary data

标签 go struct

tl;博士 我有一个由节点结构定义的任意有向图。 我现在希望能够提供一种方法来编写遍历此图的函数,并使用特定于该函数的元数据“标记”每个节点。

例如,考虑一个计算节点数的函数:

type Node struct {
    Nexts []*Node
}

func CountNodes(root *Node) int {
    m := make(map[*Node]bool)
    return countNodesHelper(root, m)
}

func countNodesHelper(root *Node, m map[*Node]bool) int {
    _, seen := m[root]
    if seen {
        return 0
    }
    m[root] = true
    c := 1
    for _, child := range root.Nexts {
        c += countNodesHelper(child, m)
    }
    return c
}

func main() {
    n1 := &Node{make([]*Node, 0, 1)}
    n2 := &Node{[]*Node{n1}}
    n1.Nexts = append(n1.Nexts, n2)
    fmt.Println(CountNodes(n1))
}

如果我在结构中添加一个“seen”标签,我可以重写它:

type NodeWithTag struct {
    Nexts []*NodeWithTag
    Seen  bool
}

func CountNodesWithTag(root *NodeWithTag) int {
    if root.Seen {
        return 0
    }
    root.Seen = true
    c := 1
    for _, child := range root.Nexts {
        c += CountNodesWithTag(child)
    }
    return c
}

func main() {
    n1 := &NodeWithTag{make([]*NodeWithTag, 0, 1), false}
    n2 := &NodeWithTag{[]*NodeWithTag{n1}, false}
    n1.Nexts = append(n1.Nexts, n2)
    fmt.Println(CountNodesWithTag(n1))
}

但 Seen 标签还不够,比如说,我还想找到向后边的树上的 DFS(你需要数到 2 -- 从未见过,见过,沿着单个树第二次见过小路)。所以,我想要一些方法来允许函数的实现使用它自己的类型来标记结构。大致相当于:

type Node struct {
  ...
  // Not valid golang
  void* tag
}

但比 void* 更安全——函数应该能够静态验证标签是否是它期望的当前类型。有没有办法做到这一点/替代方法。

我想将标签与节点相关联(而不是标签的单独映射/存储)的原因是允许使用此类标签的函数轻松并行化,将节点分配给不同的 goroutines。在第一种方法中, map 必须在 goroutine 之间共享,这很快就会成为瓶颈,因为它需要同步访问。

最佳答案

如果你需要支持任意数据类型,你需要使用一个空接口(interface):

type NodeWithTag struct {
    Nexts []*NodeWithTag
    Tag   interface{}
}

您可以为 Tag 字段分配任何值。如果你想验证值是某种类型,比如 MyType,你可以使用类型断言:

myVal, ok := node.Tag.(MyType)

如果值属于该类型,ok 将为真,myVal 将包含键入的值。

关于戈朗 : Preferred way to tag a struct with aribtrary data,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47128480/

相关文章:

c - golang exec.Command 无法运行 C 二进制文件

c - 如何使用 __declspec( dllexport/import ) 从 DLL 导出/导入 C 结构/到控制台应用程序

go - 当我在 Goroutine 中填充它时,为什么这张 map 是空的?

c++ - 二叉树插入法导致栈溢出

c++ - const char * 在 while 循环的下一次迭代中被覆盖

C++ 命名管道客户端不会读取超过 4096 字节

go - 为什么调用函数时要使用 `go` 关键字?

go - 如何解释golang slice range的现象

debugging - 是否有适用于 GoLang 的 CLI(命令行界面)?

c++ - 将包含 unique_ptr 的结构项添加到 STL 容器