使用嵌套映射复制struct

时间:2018-04-08 22:36:56

标签: pointers go reference

我想做什么?

复制"默认"在需要时构建一个新的,保留所有值。

详情

我正在尝试复制Chat结构:

type ChatData struct {
        User map[string]map[string]string `json:"user"`
        Chat map[string]string            `json:"chat"`
}
type Chat struct {
        Settings map[string]map[string]interface{} `json:"settings"`
        Data     ChatData                          `json:"data"`
}

我只需要在引入新聊天时执行此操作,并检查map[string]Chat中的成员资格。

//data is a map[string]Chat
if _, exists := data[event.Chat]; !exists {
        data[event.Chat] = data["default"]
}

完整的默认结构是:

{
    "default": {
        "settings": {
            "eightball": {
                "messages": [
                    "yes",
                    "no",
                    "maybe"
                ]   
            },  
            "main": {
                "blacklistedCommands": [], 
                "blacklistedUsers": [], 
                "error": "there was an error - ",
                "maxConsecutive": 5,
                "permissions": "You don't have permissions for that command.",
                "success": "The command was successful.",
                "whitelistedCommands": [], 
                "whitelistedUsers": []
            }   
        },  
        "data": {
            "user": {
                "default": {
                    "admin": "false",
                    "consecutiveCommands": "0",
                    "nickname": "", 
                    "sentMessages": "0" 
                },  
                "total": {
                    "admin": "false",
                    "consecutiveCommands": "0",
                    "nickname": "", 
                    "sentMessages": "0" 
                }   
            },  
            "chat": {
                "commandSender": "", 
                "lastMessage": "", 
                "lastSender": "", 
                "lastTimestamp": "", 
                "wasCommand":""
            }
        }
    }
}

我尝试了什么

data[event.Chat] = data["default"]
// causes a reference

data[event.Chat] = &data["default"]
// cannot use &data["default"] (type *Chat) as type Chat in assignment

data[event.Chat] = *data["default"]
// invalid indirect of data["default"] (type Chat)

我是否需要将map[string]Chat的使用更改为map[string]*Chat并使用第二个选项?指针和参考文献不是我的专长,所以请帮助。

修改

谁认为我在复制地图,你在吸什么?

3 个答案:

答案 0 :(得分:2)

我在之前的案例中发现,复制复杂结构的一种简单(虽然不是最有效)的方法是对其进行Marshal,然后将其解组为一个新变量。这可以通过各种编码来完成。两个简单的(包括在stdlib中)将是json和gob。

还有很多图书馆使用反射来实现类似的目标:https://github.com/jinzhu/copier

但就像我说的那样,虽然效率不高,但这很容易理解,只需要一个简单的功能即可实现。如果表现很重要,你应该选择gob而不是json。如果性能真的很重要,那么你应该更喜欢另一种解决方案。

答案 1 :(得分:1)

如果您了解数据结构,则最好完全定义结构。它比复杂的地图和具有反射的界面更易于管理数据类型。这是一个帮助您将JSON转换为Go结构的工具。它并不完美,您必须确认数据类型。您甚至可能想要删除内部结构并为它们创建类型以便于阅读和维护,但它会为您节省一些时间。

https://mholt.github.io/json-to-go/

package main

import (
    "encoding/json"
    "fmt"
    "log"
)

var rawDataExample = []byte(`{
    "default": {
        "settings": {
            "eightball": {
                "messages": [
                    "yes",
                    "no",
                    "maybe"
                ]   
            },  
            "main": {
                "blacklistedCommands": [], 
                "blacklistedUsers": [], 
                "error": "there was an error - ",
                "maxConsecutive": 5,
                "permissions": "You don't have permissions for that command.",
                "success": "The command was successful.",
                "whitelistedCommands": [], 
                "whitelistedUsers": []
            }   
        },  
        "data": {
            "user": {
                "default": {
                    "admin": "false",
                    "consecutiveCommands": "0",
                    "nickname": "", 
                    "sentMessages": "0" 
                },  
                "total": {
                    "admin": "false",
                    "consecutiveCommands": "0",
                    "nickname": "", 
                    "sentMessages": "0" 
                }   
            },  
            "chat": {
                "commandSender": "", 
                "lastMessage": "", 
                "lastSender": "", 
                "lastTimestamp": "", 
                "wasCommand":""
            }
        }
    }
}
`)

type Settings struct {
    Default struct {
        Settings struct {
            Eightball struct {
                Messages []string `json:"messages"`
            } `json:"eightball"`
            Main struct {
                BlacklistedCommands []string `json:"blacklistedCommands"`
                BlacklistedUsers    []string `json:"blacklistedUsers"`
                Error               string   `json:"error"`
                MaxConsecutive      int      `json:"maxConsecutive"`
                Permissions         string   `json:"permissions"`
                Success             string   `json:"success"`
                WhitelistedCommands []string `json:"whitelistedCommands"`
                WhitelistedUsers    []string `json:"whitelistedUsers"`
            } `json:"main"`
        } `json:"settings"`
        Data struct {
            User struct {
                Default struct {
                    Admin               string `json:"admin"`
                    ConsecutiveCommands string `json:"consecutiveCommands"`
                    Nickname            string `json:"nickname"`
                    SentMessages        string `json:"sentMessages"`
                } `json:"default"`
                Total struct {
                    Admin               string `json:"admin"`
                    ConsecutiveCommands string `json:"consecutiveCommands"`
                    Nickname            string `json:"nickname"`
                    SentMessages        string `json:"sentMessages"`
                } `json:"total"`
            } `json:"user"`
            Chat struct {
                CommandSender string `json:"commandSender"`
                LastMessage   string `json:"lastMessage"`
                LastSender    string `json:"lastSender"`
                LastTimestamp string `json:"lastTimestamp"`
                WasCommand    string `json:"wasCommand"`
            } `json:"chat"`
        } `json:"data"`
    } `json:"default"`
}

type Data struct {
    Events map[string]Settings
}

func main() {
    var settings Settings
    err := json.Unmarshal(rawDataExample, &settings)
    if err != nil {
        log.Fatal(err)
    }

    event := "foo"
    d := Data{
        Events: make(map[string]Settings),
    }

    if _, ok := d.Events[event]; !ok {
        // event doesn't exist
        // add it
        d.Events[event] = settings
        fmt.Println("event added")
    }

    if _, ok := d.Events[event]; !ok {
        // event exist, this will never be happen
        // sanity check
        fmt.Println("this will never be printed")
    }

    fmt.Printf("%+v\n", d)

}

答案 2 :(得分:-1)

超级简单的修复,只是想在我做之前得到一些输入。更改了map[string]Chat> map[string]*Chat并制作了新的*Chat,然后复制了数据。

data[event.Chat] = &Chat{}
*data[event.Chat] = *data["default"]