golang:使用aribtrary数据标记结构的首选方法

时间:2017-11-06 01:25:44

标签: go struct

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

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

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))
}

如果我在struct中添加了“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 * - 该函数应该能够静态验证标记是否是它所期望的当前类型。有没有办法做到这一点/另一种方法。

我想将标记与Node(而不是标记的单独地图/存储)相关联的原因是为了允许使用这些标记的函数的简单并行化,将节点分配到不同的goroutine。在第一种方法中,地图必须在goroutine之间共享,这很快就会成为瓶颈,因为它需要同步访问。

1 个答案:

答案 0 :(得分:1)

如果您需要支持任意数据类型,则需要使用空接口:

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

您可以为Tag字段指定任何值。如果要验证该值是否为某种类型,例如MyType,则可以使用类型断言:

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

如果值属于该类型,则ok将为true,myVal将包含输入的值。