Golang中递归与值传递/引用传递的对比解析

Golang中递归与值传递/引用传递的对比解析 我正在尝试用Golang复现这个解决方案(https://stackoverflow.com/questions/49116223/convert-antlr-parse-tree-to-json)。但我没有得到预期的嵌套映射,只得到了头节点。以下是我目前的代码:

附上我的解析树和调试输出的截图。 非常感谢:

package main

import (
    "encoding/json"
    "reflect"
    "strconv"
    "strings"
    "time"

    "../parser"
    "./docker"
    "./kubernetes"
    "./orchestrator"
    "./utils"
    "github.com/antlr/antlr4/runtime/Go/antlr"
    "github.com/emirpasic/gods/lists/arraylist"
    "github.com/emirpasic/gods/maps/linkedhashmap"
)

func toMap(tree antlr.Tree) *linkedhashmap.Map {
    m := linkedhashmap.New()
    traverseMap(tree, m)
    return m
}

func traverseMap(tree antlr.Tree, m *linkedhashmap.Map) {
    if (reflect.TypeOf(tree) == reflect.TypeOf(&antlr.TerminalNodeImpl{})) {
        token := tree.(antlr.TerminalNode).GetSymbol()
        m.Put("type", token.GetTokenType())
        m.Put("text", token.GetText())

    } else {
        children := arraylist.New()
        s := reflect.ValueOf(tree).Type().Elem().Name()
        m.Put(s, children)
        for i := 0; i < tree.GetChildCount(); i++ {
            nested := linkedhashmap.New()
            children.Add(nested)
            traverseMap(tree.GetChild(i), nested)
        }
    }
}

func main() {
    input, _ := antlr.NewFileStream("../input/sample-mvbag-rich.toml")
    lexer := parser.NewVeloLexer(input)
    stream := antlr.NewCommonTokenStream(lexer, 0)
    p := parser.NewVeloParser(stream)
    p.RemoveErrorListeners()
    p.AddErrorListener(errorListiner)
    p.BuildParseTrees = true
    tree := p.Velo()
    j := toMap(tree)
    println(j.Size())
    strB, _ := j.ToJSON()
    print(string(strB))
    //antlr.ParseTreeWalkerDefault.Walk(NewVeloListener(), tree)
}

08


更多关于Golang中递归与值传递/引用传递的对比解析的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于Golang中递归与值传递/引用传递的对比解析的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


在Golang中处理递归数据结构时,理解值传递和引用传递的机制至关重要。从您的代码来看,问题可能出现在递归遍历过程中对映射的处理方式上。

以下是改进后的代码示例,展示了如何正确使用引用传递来处理嵌套映射结构:

func toMap(tree antlr.Tree) *linkedhashmap.Map {
    m := linkedhashmap.New()
    traverseMap(tree, m)
    return m
}

func traverseMap(tree antlr.Tree, m *linkedhashmap.Map) {
    if terminalNode, ok := tree.(antlr.TerminalNode); ok {
        token := terminalNode.GetSymbol()
        m.Put("type", token.GetTokenType())
        m.Put("text", token.GetText())
    } else {
        // 使用类型断言替代反射
        node := tree.(antlr.RuleNode)
        ruleName := node.GetRuleContext().GetRuleIndex()
        
        children := arraylist.New()
        m.Put("rule", ruleName)
        m.Put("children", children)
        
        for i := 0; i < node.GetChildCount(); i++ {
            child := node.GetChild(i)
            nested := linkedhashmap.New()
            children.Add(nested)
            // 这里传递的是nested的引用,确保递归调用能修改同一个映射
            traverseMap(child, nested)
        }
    }
}

// 测试函数展示递归和映射传递
func testRecursiveMap() {
    input := `key = "value"`
    lexer := parser.NewVeloLexer(antlr.NewInputStream(input))
    stream := antlr.NewCommonTokenStream(lexer, 0)
    p := parser.NewVeloParser(stream)
    tree := p.Velo()
    
    result := toMap(tree)
    jsonData, _ := json.MarshalIndent(result, "", "  ")
    fmt.Println(string(jsonData))
}

关键改进点:

  1. 使用类型断言替代反射,提高性能和可读性:
if terminalNode, ok := tree.(antlr.TerminalNode); ok {
    // 处理终端节点
} else if ruleNode, ok := tree.(antlr.RuleNode); ok {
    // 处理规则节点
}
  1. 确保在递归过程中正确传递映射引用:
nested := linkedhashmap.New()
children.Add(nested)
traverseMap(child, nested) // nested作为引用传递
  1. 使用更清晰的数据结构:
m.Put("rule", ruleName)
m.Put("children", children)

这个实现利用了Golang的引用传递特性,确保在递归调用中所有操作都作用于同一个映射实例,从而正确构建嵌套的JSON结构。

回到顶部