英文:
Custom unmarshalling from flat json to nested struct
问题
假设我有两个相关的结构体,如下所示:
type SecretUser struct {
    UserInfo `json:"userInfo"`
    Password string `json:"password"`
}
type UserInfo struct {
    FirstName string `json:"firstName"`
    LastName  string `json:"lastName"`
    Email     string `json:"email"`
}
我收到的JSON数据如下所示:
{
    "firstName": "nice",
    "lastName": "guy",
    "email": "nice@guy.co.uk",
    "password": "abc123"
}
我想将这个JSON数据解组成一个SecretUser结构体。有没有比下面这种方法更好的方式?
func (u *User) UnmarshalJSON(data []byte) error {
    var objmap map[string]*json.RawMessage
    var password string
    var err error
    err = json.Unmarshal(data, &objmap)
    if err != nil {
        return err
    }
    if err := json.Unmarshal(data, &u.UserInfo); err != nil {
        return err
    }
    
    err = json.Unmarshal(*objmap["password"], &password)
    if err != nil {
        return err
    }
    u.Password = password
    return nil
}
基本上,我将JSON数据部分解组成一个UserInfo结构体,然后再次读取它以提取密码。我不想为了清晰地解组这个JSON数据而创建另一个结构体,也不想使用外部库(除非它是标准库的一部分)。有没有更清晰/高效的方法来做到这一点,而不需要两次读取JSON数据或手动从映射中设置每个字段?
英文:
Lets say I have two struct that are related like this:
type SecretUser struct {
	UserInfo `json:"userInfo"`
	Password string `json:"password"`
}
type UserInfo struct {
	FirstName string `json:"firstName"`
	LastName  string `json:"lastName"`
	Email     string `json:"email"`
}
And I receive a JSON in this form:
{
	"firstName": "nice",
	"lastName":"guy",
	"email":"nice@guy.co.uk",
	"password":"abc123"
}
I want to unmarshall this JSON into a SecretUser. Is there a better way than doing it like this?
func (u *User) UnmarshalJSON(data []byte) error {
	var objmap map[string]*json.RawMessage
	var password string
	var err error
	err = json.Unmarshal(data, &objmap)
	if err != nil {
		return err
	}
	if err := json.Unmarshal(data, &u.UserInfo); err != nil {
		return err
	}
	
	err = json.Unmarshal(*objmap["password"], &password)
	if err != nil {
		return err
	}
	u.Password = password
	return nil
}
Basically, I partially unmarshall the JSON into a UserInfo struct and then read it again to extract the password. I don't want to create another struct for just unmarshalling this JSON cleanly or use an external library (unless it's part of the standard). Is there a more clean/efficient way of doing this, without reading the JSON twice or setting every field manually from a map?
答案1
得分: 1
只需将UserData包含在SecretUser结构体中,并且不为其指定json标签。
type UserInfo struct {
    FirstName string `json:"firstName"`
    LastName  string `json:"lastName"`
    Email     string `json:"email"`
}
type SecretUser struct {
    UserInfo
    Password string `json:"password"`
}
func main() {
    data := []byte(`{"firstName": "nice","lastName":"guy","email":"nice@guy.co.uk","password":"abc123"}`)
    var u SecretUser
    json.Unmarshal(data, &u)
    fmt.Println(u)
}
英文:
Simply include the UserData into the SecretUser struct and do not specify a json tag for it.
type UserInfo struct {
	FirstName string `json:"firstName"`
	LastName  string `json:"lastName"`
	Email     string `json:"email"`
}
type SecretUser struct {
	UserInfo
	Password string `json:"password"`
}
func main() {
	data := []byte(`{"firstName": "nice","lastName":"guy","email":"nice@guy.co.uk","password":"abc123"}`)
	var u SecretUser
	json.Unmarshal(data, &u)
	fmt.Println(u)
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论