1. json
In Go, JSON serialization and deserialization are usually passed through the standard libraryencoding/json
To achieve it. This package provides an easy-to-use interface to convert Go data structures into JSON format strings (serialized) and parse Go data structures from JSON strings (deserialized).
1.1 Serialization (convert Go objects to JSON)
use()
Functions can convert a Go object to a JSON string.
import ( "encoding/json" "fmt" "testing" ) type TestJson struct { UserId int `json:"user_id"` // Use the structure tag to specify the key name of the field in JSON UserNickname string // If no tag is specified, the field name is used by default. UserAge int `json:"age,omitempty"` // Use omitempty to ignore null values during serialization} func Test1(t *) { tJson1 := TestJson{1, "Jackson", 18} tJson2 := new(TestJson) jsonStr1, _ := (tJson1) jsonStr2, _ := (tJson2) (string(jsonStr1)) (string(jsonStr2)) }
Output
{"user_id":1,"UserNickname":"Jackson","age":18}
{"user_id":0,"UserNickname":""}
Serialization of beautiful printing
If you need to generate well-formatted and more readable output, you can use()
func Test2(t *) { tJson1 := TestJson{1, "Jackson", 18} jsonStr1, _ := (tJson1, "", "\t") (string(jsonStr1)) }
Output
{
"user_id": 1,
"UserNickname": "Jackson",
"age": 18
}
1.2 Deserialization (convert JSON to Go object)
use()
Functions can parse a JSON string into the corresponding Go data structure.
func Test3(t *) { jsonStr := `{ "user_id": 1, "UserNickname": "Jackson", "age": 18 }` var tJson TestJson // Convert the string to a byte array and pass it into the parsed object pointer // The second parameter must be a pointer to the target data type variable so that the function can modify the variable. err := ([]byte(jsonStr), &tJson) if err != nil { ("Parse error:", err) } else { (tJson) } }
Output
{1 Jackson 18}
1.3 Note
- Field Export: Only the exported fields (i.e., the capitalization of the initial letter) can be encoded/decoded.
- Error handling: Always check for return errors to ensure the data is processed correctly.
- Extra information: Fields outside the parsed structure will be discarded
func Test5(t *) { jsonStr := `{ "user_id": 1, "UserNickname": "Jackson", "age": 18, "addr": ["Address 1","Address 2"], "info":{ "id":"2", "name":"a" } }` var tJson TestJson err := ([]byte(jsonStr), &tJson) if err != nil { ("Parse error:", err) } else { (tJson) } }
Output
{1 Jackson 18}
flexibility: For unknown or dynamic data, you can consider using map or interface{} to receive decoded results, but this will lose some type-safety features.
func Test4(t *) { jsonStr := `{ "user_id": 1, "UserNickname": "Jackson", "age": 18, "addr": ["Address 1","Address 2"], "info":{ "id":"2", "name":"a" } }` var tJson map[string]any err := ([]byte(jsonStr), &tJson) if err != nil { ("Parse error:", err) } else { (tJson) } }
Output
map[UserNickname:Jackson addr:[Address 1 Address 2] age:18 info:map[id:2 name:a] user_id:1]
2. Manual reflection implementation
encoding/json
The package uses reflection heavily internally to achieve its functionality.
Reflection in JSON serialization
- Calling
()
When Go uses reflection to check the type of incoming object. - pass
()
and()
Get type information and actual values. - Iterate through the structure field and read the label (such as
json:"name"
) and generate the corresponding JSON string according to the field type.
Reflection in JSON deserialization
- Calling
()
When Go uses the target variable pointer to determine the data structure to be filled through reflection. - According to the key names in the JSON data, find the corresponding structure field through the label map and set its value.
2.1 json simple serialization
Idea: Imitationencoding/json
Library, read the field name specified by the structure tag
- Reflected incoming structure
- Get fields
- Tags for judged fields
- Stitching strings
func serializeSimple(data interface{}) string { var resultStr string = "{" //1. Reflected incoming structure reflectDataValue := (data) reflectDataType := () if () == { reflectDataValue = () } if () == { reflectDataType = () } //2. Get the field for i := 0; i < (); i++ { field := (i) // Field name var filedName = // field value filedValue := (i).Interface() //3. Determine the label of the field if value, ok := ("json"); ok { // If there is a json tag, use the name of its definition filedName = (value, ",omitempty", "") // Is it ignoring the empty value if (value, "omitempty") { if filedValue == "" || filedValue == 0 { continue } } } // Stitching json resultStr += ("\"%s\":\"%v\"", filedName, filedValue) resultStr += "," } //4. Splice string resultStr += "}" // Remove the ending number return (resultStr, ",}", "}") } func Test6(t *) { tJson1 := TestJson{1, "Jackson", 18} tJson2 := new(TestJson) jsonStr1, _ := (tJson1) jsonStr2, _ := (tJson2) (string(jsonStr1)) (string(jsonStr2)) ("=========Custom implementation=========") (serializeSimple(tJson1)) (serializeSimple(tJson2)) }
Output
{"user_id":1,"UserNickname":"Jackson","age":18}
{"user_id":0,"UserNickname":""}
=========== Custom implementation=============
{"user_id":"1","UserNickname":"Jackson","age":"18"}
{"user_id":"0","UserNickname":""}
2.2 json simple deserialization
Ideas
- Cut incoming strings and split them into key value pairs
- Reflect structure, determine the structure label and generate a map of the field and value
- Determine the field type and set the value of the corresponding type
func parseSimple(str string, dataTemp interface{}) { // JSON format data to determine whether it is standard if str != "" && str[0] == '{' && str[len(str)-1] == '}' { // Replace the {} before and after str = ((str, "{", ""), "}", "") // After parsing the label of the structure, stuff it into the map alternate: map [field name] field address structMap := map[string]{} // Get field name through reflection rValue := (dataTemp) if () == { rValue = () } rType := () for i := 0; i < (); i++ { name := (i).Name // If there is a defined tag, use the field name of the tag if lookup, ok := (i).("json"); ok { name = (lookup, ",omitempty", "") } // Map field names and values structMap[name] = (i) } // According to, cut each key value pair splitList := (str, ",") for i := range splitList { s := splitList[i] // According to: Cut out key and value keyValue := (s, ":") key := keyValue[0] key = ((key), "\"", "") // Remove the spaces before and after value := keyValue[1] value = ((value), "\"", "") // Push value back into the structure according to the key switch structMap[key].Type().Kind() { // Pay attention to the type of judgment. Currently, only int and string are written, and other similar case : intValue, _ := (value) structMap[key].SetInt(int64(intValue)) case : structMap[key].SetString(value) default: panic("Data types not supported yet") } } } } func Test7(t *) { jsonStr := `{ "user_id": 1, "UserNickname": "Jackson", "age": 18 }` var tJson1 TestJson var tJson2 TestJson err := ([]byte(jsonStr), &tJson1) if err != nil { ("Parse error:", err) } else { (tJson1) } ("=========Custom implementation=========") parseSimple(jsonStr, &tJson2) (tJson2) }
2.3 Problem
- Only process structure-type data and does not support nested complex data structures (such as slices or mappings)
- In the serialized implementation, integers or booleans are converted to quoted strings.
- Complex structures do not support them, problems may occur
Therefore, manually implementing JSON serialization and deserialization only helps us better understand the mapping relationship between data format and programming language. In actual development, use standard librariesencoding/json
is a more efficient and reliable approach as it has taken into account many complex situations and has performed performance optimization.
2.4 Summary
2.4.1 What is the difference between single and double quotes defined strings
In the example of json simple deserialization, single and double quotes are used to define different types of character data. What are the specific differences?
Single quotes ('
):
- Single quotes are used to represent a character (rune). In Go,
rune
is an alias, representingint32
Type, used to represent Unicode code points. - A character constant enclosed in single quotes can only contain one character. For example:
'a'
,'middle'
,'😊'
。
Double quotes ("
):
- Double quotes are used to define strings. A string is a data type composed of a series of bytes and can contain zero or more characters.
- A string may include escape sequences, for example:
\n
,\t
,\"
wait. - For example: "hello", "world", "Go is fun\n".
2.4.2 How to convert string to int
In the example of json simple deserialization,The function will string (
string
) converts to integer (int
), in addition to this
-
Function converts string to
int
type. If the conversion is successful, it returns the converted integer andnil
Error; if it fails, it returns0
and error. -
Function converts string to
int64
type and allows you to specify cardinality and bit size. If you need to convert toint
Type, you may need to decide how to handle the results based on the platform (32-bit or 64-bit).
func Test8(t *) { str := "123" // The second parameter is the cardinality, 10 means decimal // The third parameter is the bit size, 0 means int64, 32 means int32, using 32 or 64 depends on your system architecture num, err := (str, 10, 0) if err != nil { ("Conversion error:", err) } else { ("Conversion result:", num) // If you need int32, you can convert it like this num32 := int32(num) ("Convert to int32 result:", num32) // If you need int, you can convert it like this (note: on 32-bit systems this will be int32, on 64-bit systems this will be int64) numInt := int(num) ("Convert to int result:", numInt) } }
Output:
Conversion result: 123
Convert to int32 result: 123
Convert to int result: 123
This is the article about golang manually implementing json serialization through reflection. For more related golang json serialization content, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!