如何读取具有结构体地址的接口值

huangapple go评论96阅读模式
英文:

How read interface value having address of struct

问题

我有一个数据类型为interface{}的变量,并将结构体的地址传递给它。现在我无法从接口中读取字段。

以下是代码:

  1. type UserData struct {
  2. UserID string `json:"user_id"`
  3. UserName string `json:"user_name"`
  4. }
  5. type Result struct {
  6. Status string `json:"status"`
  7. Data interface{} `json:"data"`
  8. }
  9. var res Result
  10. res.Data = &UserData{}
  11. json.Unmarshal([]byte(`{"status": "success", "data": {"user_id":15,"user_name":"abc"}}`), &res)
  12. fmt.Println(res.Data) // 正常工作
  13. fmt.Println(res.Data.UserName) // 出错:类型interface{}没有字段或方法UserName

如果我使用res.Data.UserName会出错。

如何从接口中读取结构体字段?

英文:

I have variable with data type interface{} and passing address of struct to it. now I unable read fields from interface

code as below:

  1. type UserData struct {
  2. UserID string `json:"user_id"`
  3. UserName string `json:"user_name"`
  4. }
  5. type Result struct {
  6. Status string `json:"status"`
  7. Data interface{} `json:"data"`
  8. }
  9. var res Result
  10. res.Data = &UserData
  11. json.Unmarshal([]byte(`{"status": "success", "data": {"user_id":15,"user_name":"abc"}}`), &res)
  12. fmt.Println(res.Data) //working fine
  13. fmt.Println(res.Data.UserName) //getting error: type interface{} has no field or method UserName

if I use res.Data.UserName getting error

How to read struct fields from interface?

答案1

得分: 2

这与https://stackoverflow.com/questions/76284655/golang-why-does-field-not-existed-in-go-struct-still-present-after-marshaling-sa进行比较很有趣。起初我以为它们是相同的。但事实证明它们并不相同。

对于这个问题,res.Data保存的是*UserData类型的值。所以一个简单的类型断言就可以解决。

以下是一个示例代码,合并了@mkopriva的两个示例,并展示了它们之间的区别:

  1. package main
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "log"
  6. )
  7. type DBBatch struct {
  8. FieldtoKeep string `json:"field_to_keep"`
  9. FieldtoKeep2 string `json:"field_to_keep2"`
  10. }
  11. func main() {
  12. jsonBatch := `{"field_to_keep":"XXXXX","field_to_keep2":"26400527","field_to_delete":"whynotdeleted"}`
  13. var i interface{} = DBBatch{}
  14. fmt.Printf("%T\n", i) // 类型是DBBatch
  15. if err := json.Unmarshal([]byte(jsonBatch), &i); err != nil {
  16. log.Println(err)
  17. }
  18. fmt.Printf("%T\n", i) // 类型不再是DBBatch,而是map[string]interface{}
  19. i = &DBBatch{}
  20. fmt.Printf("%T\n", i) // 类型是*DBBatch
  21. if err := json.Unmarshal([]byte(jsonBatch), &i); err != nil {
  22. log.Println(err)
  23. }
  24. fmt.Printf("%T\n", i) // 类型是*DBBatch
  25. }

输出结果为:

  1. main.DBBatch
  2. map[string]interface {}
  3. *main.DBBatch
  4. *main.DBBatch
英文:

It's interesting to compare this with https://stackoverflow.com/questions/76284655/golang-why-does-field-not-existed-in-go-struct-still-present-after-marshaling-sa. At first I thought they are the same. But it turns out that they are not.

For this question, res.Data holds a value of type *UserData. So a simple type assertion will work.

  1. package main
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. )
  6. type UserData struct {
  7. UserID string `json:"user_id"`
  8. UserName string `json:"user_name"`
  9. }
  10. type Result struct {
  11. Status string `json:"status"`
  12. Data interface{} `json:"data"`
  13. }
  14. func main() {
  15. var res Result
  16. res.Data = &UserData{}
  17. json.Unmarshal([]byte(`{"status": "success", "data": {"user_id":15,"user_name":"abc"}}`), &res)
  18. fmt.Println(res.Data)
  19. fmt.Println(res.Data.(*UserData).UserName)
  20. }

The following demo is a merge of @mkopriva's two demos, and it shows the difference:

  1. package main
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "log"
  6. )
  7. type DBBatch struct {
  8. FieldtoKeep string `json:"field_to_keep"`
  9. FieldtoKeep2 string `json:"field_to_keep2"`
  10. }
  11. func main() {
  12. jsonBatch := `{"field_to_keep":"XXXXX","field_to_keep2":"26400527","field_to_delete":"whynotdeleted"}`
  13. var i interface{} = DBBatch{}
  14. fmt.Printf("%T\n", i) // type is DBBatch
  15. if err := json.Unmarshal([]byte(jsonBatch), &i); err != nil {
  16. log.Println(err)
  17. }
  18. fmt.Printf("%T\n", i) // type is not DBBatch anymore, instead it's map[string]any
  19. i = &DBBatch{}
  20. fmt.Printf("%T\n", i) // type is *DBBatch
  21. if err := json.Unmarshal([]byte(jsonBatch), &i); err != nil {
  22. log.Println(err)
  23. }
  24. fmt.Printf("%T\n", i) // type is *DBBatch
  25. }

The output is:

  1. main.DBBatch
  2. map[string]interface {}
  3. *main.DBBatch
  4. *main.DBBatch

huangapple
  • 本文由 发表于 2023年5月27日 16:43:01
  • 转载请务必保留本文链接:https://go.coder-hub.com/76346054.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定