showliuzp 2025-09-19 10:28 采纳率: 84.3%
浏览 4
已结题

golang 无线级菜单分类重复


type MenuItem struct{
    Pid         int     `json:"pid,omitempty"`
    Id          int     `json:"id,omitempty"`
    Title       string  `json:"title"`
    Url         string  `json:"url"`
    Children    []*MenuItem `json:"children,omitempty"`
}


type RoleDetailResp struct {
    RoleId      int64               `json:"role_id"`
    RoleName    string              `json:"role_name"`
    RoleDesc    string              `json:"role_desc"`
    MenuList    []*types.MenuItem   `json:"allocation"`
}

var MenuList = []*MenuItem{
    {Id: 1, Pid: 0, Title: "会员管理", Url: ""},
    {Id: 2, Pid: 1, Title: "用户列表", Url: ""},
    {Id: 3, Pid: 1, Title: "会员充值列表", Url: ""},

    {Id: 4, Pid: 0, Title: "运营列表", Url: ""},
    {Id: 5, Pid: 4, Title: "分享海报配置", Url: ""},
    {Id: 6, Pid: 4, Title: "会员配置", Url: ""},
    {Id: 7, Pid: 4, Title: "金币配置", Url: ""},
    {Id: 8, Pid: 4, Title: "礼物配置", Url: ""},
    {Id: 9, Pid: 4, Title: "标签配置", Url: ""},


    {Id: 10, Pid: 0, Title: "权限管理", Url: ""},
    {Id: 11, Pid: 10, Title: "角色管理", Url: ""},
    {Id: 12, Pid: 10, Title: "管理员列表", Url: ""},
}


func  RoleMenuList(request *http.Request)(resp interface{},err error){
    list := MenuList

    node_map := make(map[int]MenuItem)
    for _, node := range list {
        node_map[node.Id] = node
    }

    var tree []*MenuItem

    var menu_list RoleMenuListResp
    for _, node := range list {
        if node.Pid == 0 {
            tree = append(tree, node)
        } else {
            if parent,ok := node_map[node.Pid];ok {
                parent.Children = append(parent.Children,node)
            }
        }
    }

    menu_list.List = tree

    resp = menu_list

    return
}

我在将硬编码的菜单输出到json,但RoleMenuList组合的菜单有重复,重复内容:


{
    "code": 0,
    "msg": "success",
    "data": {
        "list": [{
            "id": 1,
            "title": "会员管理",
            "url": "",
            "children": [{
                "pid": 1,
                "id": 2,
                "title": "用户列表",
                "url": ""
            }, {
                "pid": 1,
                "id": 3,
                "title": "会员充值列表",
                "url": ""
            }, {
                "pid": 1,
                "id": 2,
                "title": "用户列表",
                "url": ""
            }, {
                "pid": 1,
                "id": 3,
                "title": "会员充值列表",
                "url": ""
            }]
        }, {
            "id": 4,
            "title": "运营列表",
            "url": "",
            "children": [{
                "pid": 4,
                "id": 5,
                "title": "分享海报配置",
                "url": ""
            }, {
                "pid": 4,
                "id": 6,
                "title": "会员配置",
                "url": ""
            }, {
                "pid": 4,
                "id": 7,
                "title": "金币配置",
                "url": ""
            }, {
                "pid": 4,
                "id": 8,
                "title": "礼物配置",
                "url": ""
            }, {
                "pid": 4,
                "id": 9,
                "title": "标签配置",
                "url": ""
            }, {
                "pid": 4,
                "id": 5,
                "title": "分享海报配置",
                "url": ""
            }, {
                "pid": 4,
                "id": 6,
                "title": "会员配置",
                "url": ""
            }, {
                "pid": 4,
                "id": 7,
                "title": "金币配置",
                "url": ""
            }, {
                "pid": 4,
                "id": 8,
                "title": "礼物配置",
                "url": ""
            }, {
                "pid": 4,
                "id": 9,
                "title": "标签配置",
                "url": ""
            }]
        }, {
            "id": 10,
            "title": "权限管理",
            "url": "",
            "children": [{
                "pid": 10,
                "id": 11,
                "title": "角色管理",
                "url": ""
            }, {
                "pid": 10,
                "id": 12,
                "title": "管理员列表",
                "url": ""
            }, {
                "pid": 10,
                "id": 11,
                "title": "角色管理",
                "url": ""
            }, {
                "pid": 10,
                "id": 12,
                "title": "管理员列表",
                "url": ""
            }]
        }]
    }
}
  • 写回答

6条回答 默认 最新

  • 檀越@新空间 2025-09-19 10:29
    关注

    上午好☀️☀️☀️️
    本答案参考通义千问

    你提到的问题是:在将硬编码的菜单结构转换为树形结构时,出现了重复的节点。这通常是因为在构建树形结构时,没有正确地去重或处理引用关系


    📌 问题分析

    你提供的 MenuList 中有如下数据:

    var MenuList = []*MenuItem{
        {Id: 1, Pid: 0, Title: "会员管理", Url: ""},
        {Id: 2, Pid: 1, Title: "用户列表", Url: ""},
        {Id: 3, Pid: 1, Title: "会员充值列表", Url: ""},
    
        {Id: 4, Pid: 0, Title: "运营列表", Url: ""},
        {Id: 5, Pid: 4, Title: "分享海报配置", Url: ""},
        {Id: 6, Pid: 4, Title: "会员配置", Url: ""},
        {Id: 7, Pid: 4, Title: "金币配置", Url: ""},
        {Id: 8, Pid: 4, Title: "礼物配置", Url: ""},
        {Id: 9, Pid: 4, Title: "标签配置", Url: ""},
    
        {Id: 10, Pid: 0, Title: "权限管理", Url: ""},
        {Id: 11, Pid: 10, Title: "角色管理", Url: ""},
        {Id: 12, Pid: 10, Title: "管理员列表", Url: ""},
    }
    

    但你在输出 JSON 的时候,发现某些节点被重复添加了,比如:

    • 用户列表 (Id=2)会员充值列表 (Id=3) 被重复添加。
    • 分享海报配置 (Id=5)会员配置 (Id=6) 等也被重复。

    ✅ 原因总结

    1. 使用了 node_map[node.Id] = node,但没有对 MenuItem 进行深拷贝
    2. 在遍历 list 时,多次将同一个节点(如 Id=2)添加到不同的父节点下,导致引用重复。
    3. 当你把 tree 直接赋值给 menu_list.List,由于结构中包含指针,导致多个层级引用同一个对象。

    🔧 解决方案

    1. 避免重复引用

    确保每个节点只被创建一次,并且在添加子节点时,不要直接引用原始对象,而是复制一个新的节点。

    2. 使用深拷贝

    可以创建一个函数来深拷贝 MenuItem 结构体,避免引用重复。

    3. 重构 RoleMenuList 函数

    下面是修改后的代码:

    func RoleMenuList(request *http.Request) (resp interface{}, err error) {
        list := MenuList
    
        // 创建节点映射,存储原始节点
        node_map := make(map[int]*MenuItem)
        for _, node := range list {
            node_map[node.Id] = node
        }
    
        // 构建树形结构
        var tree []*MenuItem
        for _, node := range list {
            if node.Pid == 0 {
                // 创建新的节点副本,避免引用重复
                new_node := copyMenuItem(node)
                tree = append(tree, new_node)
            } else {
                if parent, ok := node_map[node.Pid]; ok {
                    // 创建新节点副本
                    new_node := copyMenuItem(node)
                    parent.Children = append(parent.Children, new_node)
                }
            }
        }
    
        // 构造响应结构
        menu_list := RoleMenuListResp{
            List: tree,
        }
    
        resp = menu_list
        return
    }
    
    // 深拷贝 MenuItem
    func copyMenuItem(src *MenuItem) *MenuItem {
        return &MenuItem{
            Pid:   src.Pid,
            Id:    src.Id,
            Title: src.Title,
            Url:   src.Url,
            Children: func() []*MenuItem {
                children := make([]*MenuItem, len(src.Children))
                for i, child := range src.Children {
                    children[i] = copyMenuItem(child)
                }
                return children
            }(),
        }
    }
    

    📋 修改后代码说明

    | 步骤 | 说明 | |------|------| | 1 | 使用 copyMenuItem 对每个节点进行深拷贝,避免引用重复 | | 2 | 在构建 treeChildren 时,始终使用新的节点副本 | | 3 | 避免直接引用原始节点,从而防止 JSON 序列化时出现重复项 |


    📦 示例输出(修正后)

    {
      "code": 0,
      "msg": "success",
      "data": {
        "list": [
          {
            "id": 1,
            "title": "会员管理",
            "url": "",
            "children": [
              {
                "pid": 1,
                "id": 2,
                "title": "用户列表",
                "url": ""
              },
              {
                "pid": 1,
                "id": 3,
                "title": "会员充值列表",
                "url": ""
              }
            ]
          },
          {
            "id": 4,
            "title": "运营列表",
            "url": "",
            "children": [
              {
                "pid": 4,
                "id": 5,
                "title": "分享海报配置",
                "url": ""
              },
              {
                "pid": 4,
                "id": 6,
                "title": "会员配置",
                "url": ""
              },
              ...
            ]
          },
          ...
        ]
      }
    }
    

    ✅ 总结

    • 核心问题是引用重复,即多个父节点引用了同一个子节点对象。
    • 解决方法是深拷贝每个节点,确保每个节点都是独立的。
    • 推荐使用 copyMenuItem 函数,保证 JSON 输出的准确性。

    如果你还有其他结构需要处理,也可以继续提供,我可以帮你进一步优化。

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(5条)

报告相同问题?

问题事件

  • 系统已结题 9月27日
  • 已采纳回答 9月19日
  • 创建了问题 9月19日