Json unmarshal:强制转换为字符串
Json unmarshal: force into string
我有以下 Go 结构,我想将一些 Json 数据解组到其中。除了类型为 map[string]string
.
的 Values
地图外,它工作得很好
type Data struct {
Id int `jons:"id"`
Values map[string]string `json:"values"`
我的 Json 数据(我无法更改其格式)具有以下结构和样本数据:
{
id: 1,
values: {
key1: "a string value",
key2: 7
}
}
解组 json 数据失败,因为 Go 无法将值 7
解组为字符串。
json: cannot unmarshal number into Go struct field Data.Values of type string
有没有办法将 Json 值隐式转换为字符串,而不考虑感知类型?
更改 Json 数据以将值格式化为字符串,即 key2: "7"
不是一个选项。
既然json里面可以有整数或者字符串,最好是使用接口
像这样:
type Data struct {
Id int `jons:"id"`
Values map[string]interface{} `json:"values"`
}
这应该可以解决问题。
您可以使用接口和类型断言
package main
import (
"encoding/json"
"fmt"
"strconv"
)
func main() {
type Data struct {
Id int `jons:"id"`
Values map[string]interface{} `json:"values"`
}
jsonData := []byte(`{"id": 1, "values": {"key1": "a string value", "key2": 7}}`)
data := new(Data)
err := json.Unmarshal(jsonData, &data)
if err != nil {
fmt.Println(err)
}
for _, value := range data.Values {
fmt.Printf("%T\n", ToString(value))
}
}
func ToString(value interface{}) string {
str := ""
switch value.(type) {
case float64:
str = strconv.FormatFloat(value.(float64), 'f', 0, 64)
case int64:
str = strconv.FormatInt(value.(int64), 10)
case int:
str = strconv.Itoa(value.(int))
case string:
str = value.(string)
}
return str
}
您可以创建自己的字符串类型并为其实现 UnmarshalJSON 函数。
type MadSrting string
type Data struct {
Id int `jons:"id"`
Values map[string]MadString `json:"values"`
}
func (mad *MadString) UnmarshalJSON(data []byte) error {
if n := len(data); n > 1 && data[0] == '"' && data[n-1] == '"' {
return json.Unmarshal(data, (*string)(mad))
}
*mad = MadString(data)
return nil
}
您可以在地图值上使用空界面。然后使用 Sprintf 将其转换为字符串。以下是如何解组数据的示例:
package main
import (
"encoding/json"
"fmt"
)
type Data struct {
Id int `jons:"id"`
Values map[string]interface{} `json:"values"`
}
func main() {
data := `
{
"id": 1,
"values": {
"key1": "a string value",
"key2": 7
}
}
`
var d Data
err := json.Unmarshal([]byte(data), &d)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(d)
s1 := fmt.Sprintf("%v", d.Values["key1"])
fmt.Println("key1", s1)
s2 := fmt.Sprintf("%v", d.Values["key2"])
fmt.Println("key2", s2)
}
要汇总提供的答案,基本上存在三种方法:
使用自定义类型值的映射,其类型“包装”string
并实现一个 encoding/json.Unmarshaler
接口以创造性地解析来自 JSON 文件.
将子文档解组为类型 map[string]interface{}
的映射,然后在每次访问此类值时对值使用类型切换或填充其他一些数据类型 — 据推测 map[string]string
在你的例子中——来自 生成的地图(在任何一种情况下你都将使用类型切换)。
使用较低级别的 JSON 解码工具 — encoding/json.Decoder
— 并在解码阶段决定如何解码特定值,并生成 string
不管被解析的值是什么类型。
我有以下 Go 结构,我想将一些 Json 数据解组到其中。除了类型为 map[string]string
.
Values
地图外,它工作得很好
type Data struct {
Id int `jons:"id"`
Values map[string]string `json:"values"`
我的 Json 数据(我无法更改其格式)具有以下结构和样本数据:
{
id: 1,
values: {
key1: "a string value",
key2: 7
}
}
解组 json 数据失败,因为 Go 无法将值 7
解组为字符串。
json: cannot unmarshal number into Go struct field Data.Values of type string
有没有办法将 Json 值隐式转换为字符串,而不考虑感知类型?
更改 Json 数据以将值格式化为字符串,即 key2: "7"
不是一个选项。
既然json里面可以有整数或者字符串,最好是使用接口
像这样:
type Data struct {
Id int `jons:"id"`
Values map[string]interface{} `json:"values"`
}
这应该可以解决问题。
您可以使用接口和类型断言
package main import ( "encoding/json" "fmt" "strconv" ) func main() { type Data struct { Id int `jons:"id"` Values map[string]interface{} `json:"values"` } jsonData := []byte(`{"id": 1, "values": {"key1": "a string value", "key2": 7}}`) data := new(Data) err := json.Unmarshal(jsonData, &data) if err != nil { fmt.Println(err) } for _, value := range data.Values { fmt.Printf("%T\n", ToString(value)) } } func ToString(value interface{}) string { str := "" switch value.(type) { case float64: str = strconv.FormatFloat(value.(float64), 'f', 0, 64) case int64: str = strconv.FormatInt(value.(int64), 10) case int: str = strconv.Itoa(value.(int)) case string: str = value.(string) } return str }
您可以创建自己的字符串类型并为其实现 UnmarshalJSON 函数。
type MadSrting string
type Data struct {
Id int `jons:"id"`
Values map[string]MadString `json:"values"`
}
func (mad *MadString) UnmarshalJSON(data []byte) error {
if n := len(data); n > 1 && data[0] == '"' && data[n-1] == '"' {
return json.Unmarshal(data, (*string)(mad))
}
*mad = MadString(data)
return nil
}
您可以在地图值上使用空界面。然后使用 Sprintf 将其转换为字符串。以下是如何解组数据的示例:
package main
import (
"encoding/json"
"fmt"
)
type Data struct {
Id int `jons:"id"`
Values map[string]interface{} `json:"values"`
}
func main() {
data := `
{
"id": 1,
"values": {
"key1": "a string value",
"key2": 7
}
}
`
var d Data
err := json.Unmarshal([]byte(data), &d)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(d)
s1 := fmt.Sprintf("%v", d.Values["key1"])
fmt.Println("key1", s1)
s2 := fmt.Sprintf("%v", d.Values["key2"])
fmt.Println("key2", s2)
}
要汇总提供的答案,基本上存在三种方法:
使用自定义类型值的映射,其类型“包装”
string
并实现一个encoding/json.Unmarshaler
接口以创造性地解析来自 JSON 文件.将子文档解组为类型
map[string]interface{}
的映射,然后在每次访问此类值时对值使用类型切换或填充其他一些数据类型 — 据推测map[string]string
在你的例子中——来自 生成的地图(在任何一种情况下你都将使用类型切换)。使用较低级别的 JSON 解码工具 —
encoding/json.Decoder
— 并在解码阶段决定如何解码特定值,并生成string
不管被解析的值是什么类型。