英文:
unmarshal generic json in Go
问题
我是一个新的Go程序员(来自Java),我想要在Go中复现一种通用的简单使用的方式。
我想要创建一些函数,允许我对JSON字符串进行解析,以避免代码重复。
这是我的当前代码,但它不起作用:
type myStruct1 struct {
id string
name string
}
func (obj myStruct1) toString() string {
var result bytes.Buffer
result.WriteString("id : ")
result.WriteString(obj.id)
result.WriteString("\n")
result.WriteString("name : ")
result.WriteString(obj.name)
return result.String()
}
func main() {
content := `{id:"id1",name="myName"}`
object := myStruct1{}
parseJSON(content, object)
fmt.Println(object.toString())
}
func parseJSON(content string, object interface{}) {
var parsed interface{}
json.Unmarshal([]byte(content), &parsed)
}
运行这段代码后,返回的结果是:
id :
name :
你有什么想法吗?
谢谢!
英文:
I'm a new Go programmer (From Java) and I would like to reproduce a generic way which is esay to use in Java.
I want to create some function which allow me to do an Unmarshal on a JSON string in order to avoid code duplicity.
This is my current code which is not working :
type myStruct1 struct {
id string
name string
}
func (obj myStruct1) toString() string {
var result bytes.Buffer
result.WriteString("id : ")
result.WriteString(obj.id)
result.WriteString("\n")
result.WriteString("name : ")
result.WriteString(obj.name)
return result.String()
}
func main() {
content := `{id:"id1",name="myName"}`
object := myStruct1{}
parseJSON(content, object)
fmt.Println(object.toString())
}
func parseJSON(content string, object interface{}) {
var parsed interface{}
json.Unmarshal([]byte(content), &parsed)
}
This code, on run, returns me this :
id :
name :
Do you have any idea ?
Thanks
答案1
得分: 19
问题是你想要写入一个通用类型?你可能想要使用字符串映射。这在 BSON 中也适用:
var anyJson map[string]interface{}
json.Unmarshal(bytes, &anyJson)
你可以这样访问字段:
anyJson["id"].(string)
不要忘记对值进行类型断言,它们必须是正确的类型,否则会引发恐慌。(你可以在 golang 网站上阅读更多关于类型断言的内容)
英文:
The issue is you want to write to a generic type? You probably want a string map. This works with BSON anyways:
var anyJson map[string]interface{}
json.Unmarshal(bytes, &anyJson)
You'll be able to access the fields like so:
anyJson["id"].(string)
Don't forget to type assert your values, and they must be the correct type or they'll panic. (You can read more about type assertions on the golang site)
答案2
得分: 5
解析“通用 JSON”时,当你不知道它的模式时:
var parsed any
err := json.Unmarshal(jsonText, &parsed)
返回的parsed
中的any
将是map[string]any
、[]any
、nil
或单个值float64
、bool
、string
。
你可以测试类型并做出相应的反应。
import (
"encoding/json"
"fmt"
)
func test(jsonText []byte) {
// 解析
var parsed any
err := json.Unmarshal(jsonText, &parsed)
if err != nil {
panic(err) // 输入格式错误
}
// 类型特定的逻辑
switch val := parsed.(type) {
case nil:
fmt.Println("json 指定为 null")
case map[string]any:
fmt.Printf("id:%s name:%s\n", val["id"], val["name"])
case []any:
fmt.Printf("包含 %d 个项目的列表\n", len(val))
case float64:
fmt.Printf("单个数字 %f\n", val)
case bool:
fmt.Printf("单个布尔值 %v\n", val)
case string:
fmt.Printf("单个字符串 %s\n", val)
default:
panic(fmt.Errorf("意外的类型 %T", parsed))
}
}
英文:
To parse "generic JSON" when you have no idea what schema it has:
var parsed any
err := json.Unmarshal(jsonText, &parsed)
The returned any
in parsed
will be a map[string]any
or []any
or nil
or single values float64
, bool
, string
.
You can test the type and react accordingly.
import (
"encoding/json"
"fmt"
)
func test(jsonText []byte) {
// parsing
var parsed any
err := json.Unmarshal(jsonText, &parsed)
if err != nil {
panic(err) // malformed input
}
// type-specific logic
switch val := parsed.(type) {
case nil:
fmt.Println("json specifies null")
case map[string]any:
fmt.Printf("id:%s name:%s\n", val["id"], val["name"])
case []any:
fmt.Printf("list of %d items\n", len(val))
case float64:
fmt.Printf("single number %f\n", val)
case bool:
fmt.Printf("single bool %v\n", val)
case string:
fmt.Printf("single string %s\n", val)
default:
panic(fmt.Errorf("type %T unexpected", parsed))
}
}
答案3
得分: 1
Unmarshal只会设置结构体中的公开字段。
这意味着你需要修改JSON结构体,使用大写字母开头的字段名:
type myStruct1 struct {
Id string
Name string
}
这样做的原因是,JSON库在没有导出字段的情况下,无法使用反射查看字段。
英文:
Unmarshal will only set exported fields of the struct.
Which means you need to modify the json struct to use capital case letters:
type myStruct1 struct {
Id string
Name string
}
The reason behind this is that the json library does not have the ability to view fields using reflect unless they are exported.
答案4
得分: 0
你必须导出你的字段:
type myStruct1 struct {
Id string
Name string
}
请参阅文档中的导出标识符。
英文:
You have to export your fields:
type myStruct1 struct {
Id string
Name string
}
See Exported Identifiers from documentation.
答案5
得分: 0
你需要在代码中进行一些更改才能使其正常工作:
- 函数
json.Unmarshal
只能设置结构体中公开的变量,也就是以大写字母开头的变量。在myStruct1
内部,使用类似ID
和Name
的变量名。 - 你的内容不是有效的JSON。你实际上想要的是
{"ID":"id1","Name":"myName"}
。 - 你将
object
传递给了parseJSON
,但你在解析字符串时使用的是parsed
而不是object
。让parseJSON
接收一个*myStruct
(而不是interface{}
),并在解组字符串时使用该变量而不是parsed
。此外,始终处理错误返回,例如err := json.Unmarshal(content, object)
,并检查err
。
我建议你参考Golang之旅进行学习。
英文:
There are a few changes you need to make in your code to make it work:
- The function
json.Unmarshal
can only set variables inside your struct which are exported, that is, which start with capital letters. Use something likeID
andName
for your variable names insidemyStruct1
. - Your content is invalid JSON. What you actually want is
{"ID":"id1","Name":"myName"}
. - You're passing
object
toparseJSON
but you're usingparsed
instead, notobject
. MakeparseJSON
receive a*myStruct
(instead of aninterface{}
), and use that variable instead ofparsed
when unmarshalling the string. Also, always handle the error returns, likeerr := json.Unmarshal(content, object)
, and checkerr
.
I'd suggest you to do the Golang Tour
答案6
得分: -1
你还可以将文件设置为另一个结构体内部具有动态属性的对象。这样可以添加元数据,并以相同的方式读取它。
type MyFile struct {
Version string
Data map[string]interface{}
}
英文:
You can also set the file as an Object with dynamic properties inside another struct. This will let you add metadata and you read it the same way.
type MyFile struct {
Version string
Data map[string]interface{}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论