doulangbi6869 2017-11-06 01:25
浏览 71
已采纳

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

tl;dr I have an arbitrary directed graph defined by a Node struct. I now want to be able to provide a way to write functions that walk this graph and "tag" each Node with metadata specific to that function.

For example, consider a function to count the number of nodes:

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

I could rewrite this if I added a "seen" tag inside the struct:

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

But the Seen tag isn't enough for, say, a DFS on a tree where I also want to find backwards edges (you need to count up to 2 -- never seen, seen, seen a second time along a a single path). So, I want some way to allow the function's implementation to use it's own type to tag the struct with. A rough equivalent of:

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

but safer that a void* -- The function should be able to statically verify that the tag is the current type that it expects. Is there a way to do this / an alternative approach.

The reason I want to associate the tag with the Node (rather than a separate map / store of the tags) is to allow easy parallelization of the functions that use such tags, farming out the nodes to different goroutines. In the first approach, the map would have to be shared between the goroutines, and this would quickly become a bottleneck because it will require synchronized access.

  • 写回答

1条回答 默认 最新

  • dpppic5186 2017-11-06 03:28
    关注

    If you need to support arbitrary data types, you'll need to use an empty interface:

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

    You can assign any value to the Tag field. If you want to verify that the value is a certain type, say MyType, you can use a type assertion:

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

    If the value is of that type, ok will be true and myVal will contain the typed value.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 装 pytorch 的时候出了好多问题,遇到这种情况怎么处理?
  • ¥20 IOS游览器某宝手机网页版自动立即购买JavaScript脚本
  • ¥15 手机接入宽带网线,如何释放宽带全部速度
  • ¥30 关于#r语言#的问题:如何对R语言中mfgarch包中构建的garch-midas模型进行样本内长期波动率预测和样本外长期波动率预测
  • ¥15 ETLCloud 处理json多层级问题
  • ¥15 matlab中使用gurobi时报错
  • ¥15 这个主板怎么能扩出一两个sata口
  • ¥15 不是,这到底错哪儿了😭
  • ¥15 2020长安杯与连接网探
  • ¥15 关于#matlab#的问题:在模糊控制器中选出线路信息,在simulink中根据线路信息生成速度时间目标曲线(初速度为20m/s,15秒后减为0的速度时间图像)我想问线路信息是什么