Codificación y decodificación en Go
En la era actual de Internet, los formatos de datos independientes del lenguaje más utilizados son xml, Yaml, json y protobuf. Go también admite operaciones relacionadas con estos formatos de datos. A continuación se muestra una tabla comparativa.
| Nombre | XML | YAML | JSON | Protocol Buffers |
|---|---|---|---|---|
| Estructura de datos | Compleja | Más simple | Simple | Más compleja |
| Modo de almacenamiento | Texto | Texto | Texto | Binario |
| Tamaño de almacenamiento | Grande | Mediano | Mediano | Pequeño |
| Eficiencia de análisis | Lenta | Media | Media | Rápida |
| Soporte de lenguajes | Muchos | Muchos | Muchos | Varios |
| Dificultad de desarrollo | Complejo | Más simple | Simple | Simple |
| Costo de aprendizaje | Bajo | Bajo | Bajo | Bajo |
| Ámbito de aplicación | Intercambio de datos | Archivo de configuración | Intercambio de datos | Intercambio de datos |
TIP
En Go, si desea serializar y deserializar una estructura, los campos deben ser exportados, es decir, la primera letra debe ser mayúscula.
Además, TOML también está comenzando a popularizarse. La sintaxis es similar a una mejora de .ini. Si está interesado, puede visitar TOML: La (semántica) obvia y (configuración) lenguaje minimalista de Tom para obtener más información.
XML
xml, también conocido como eXtensible Markup Language, es un formato para almacenar datos que se originó en la década de 1960 y es el formato de datos más antiguo mencionado anteriormente. Tiene una amplia gama de aplicaciones y se puede utilizar para la transmisión de red, el intercambio de datos, archivos de configuración, almacenamiento de datos, etc. Sin embargo, con el paso del tiempo, está siendo gradualmente reemplazado por nuevos lenguajes de marcado.
Primero, definamos la estructura
type Person struct {
UserId string `xml:"id"`
Username string `xml:"name"`
Age int `xml:"age"`
Address string `xml:"address"`
}func Marshal(v any) ([]byte, error) //Serialización xml
func MarshalIndent(v any, prefix, indent string) ([]byte, error) //Formateo
func Unmarshal(data []byte, v any) error //DeserializaciónSerialización
func main() {
person := Person{
UserId: "120",
Username: "jack",
Age: 18,
Address: "usa",
}
bytes, err := xml.MarshalIndent(person, "", "\t")
if err != nil {
fmt.Println(err)
return
}
fmt.Println(string(bytes))
}Salida
<Person>
<id>120</id>
<name>jack</name>
<age>18</age>
<address>usa</address>
</Person>Deserialización
func main() {
var person = Person{
UserId: "",
Username: "",
Age: 0,
Address: "",
}
xmlStr := "<Person> \n <id>120</id> \n <name>jack</name> \n <age>18</age> \n <address>usa</address>\n</Person> "
err := xml.Unmarshal([]byte(xmlStr), &person)
if err != nil {
fmt.Println(err)
return
}
}Salida
{UserId:120 Username:jack Age:18 Address:usa}Sin embargo, el método tradicional de análisis XML a menudo requiere crear estructuras, lo cual puede ser muy tedioso. Ahora, el análisis XML es simple. Si se utiliza una estructura compleja, puede ser muy problemático. Por lo tanto, la mayoría de las veces usaremos una biblioteca de código abierto de terceros etree para analizar XML. Si está interesado, puede obtener más información por su cuenta: Plugin etree útil para analizar archivos XML en Go - Juejin (juejin.cn).
YML
La sintaxis de YAML es similar a otros lenguajes de alto nivel y puede expresar simplemente listas, mapas, escalares y otras formas de datos. Utiliza símbolos de espacio en blanco para la sangría y depende en gran medida de las características de apariencia, lo que lo hace especialmente adecuado para expresar o editar estructuras de datos y varios archivos de configuración. YML también existe en muchos proyectos en forma de archivos de configuración, y su estructura de contenido es más concisa y clara de un vistazo. Go oficial no proporciona soporte para YML, necesitamos usar un paquete de terceros.
go get github.com/go-yaml/yamlMétodos principales
func Marshal(in interface{}) (out []byte, err error) //Serialización
func Unmarshal(in []byte, out interface{}) (err error) //DeserializaciónPrimero, preparemos la estructura
type Config struct {
Database string `yaml:"database"`
Url string `yaml:"url"`
Port int `yaml:"port"`
Username string `yaml:"username"`
Password string `yaml:"password"`
}Archivo de configuración
database: mysql
url: 127.0.0.1
port: 3306
username: root
password: 123456Serialización
func main() {
config := Config{
Database: "oracle",
Url: "localhost",
Port: 3326,
Username: "root",
Password: "123456",
}
out, err := yaml.Marshal(config)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(string(out))
}Salida
database: oracle
url: localhost
port: 3326
username: root
password: "123456"Sin embargo, debido a que yml tiene una sintaxis de sangría estricta, no hay problemas con el formato de serialización.
Deserialización
func main() {
bytes, err := os.ReadFile("./src/config.yml")
if err != nil {
fmt.Println(err)
return
}
var config Config
err = yaml.Unmarshal(bytes, &config)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(config)
}Salida
{mysql 127.0.0.1 3306 root 123456}JSON
json se usa a menudo en la comunicación de interfaces de estilo Restful. En comparación con xml, su tamaño más ligero y su bajo costo de aprendizaje lo han convertido en el formato de intercambio de datos dominante en el campo web.
En Go, el paquete encoding/json proporciona funciones correspondientes para realizar la serialización y deserialización de JSON. Las funciones principales son las siguientes.
func Marshal(v any) ([]byte, error) //Serializa un objeto Go a una cadena JSON
func Unmarshal(data []byte, v any) error //Deserializa una cadena JSON a un objeto GoPrimero, definamos la estructura
type Person struct {
UserId string
Username string
Age int
Address string
}Serialización
func main() {
person := Person{
UserId: "120",
Username: "jack",
Age: 18,
Address: "usa",
}
bytes, err := json.Marshal(person)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(string(bytes))
}Resultado
{ "UserId": "120", "Username": "jack", "Age": 18, "Address": "usa" }Renombramiento de campos
Podemos lograr el efecto de renombramiento a través de etiquetas de estructura.
type Person struct {
UserId string `json:"id"`
Username string `json:"name"`
Age int `json:"age"`
Address string `json:"address"`
}Salida en este momento
{ "id": "1202", "name": "jack", "age": 19, "address": "USA" }Sangría
La serialización no tiene sangría de forma predeterminada. Esto es para reducir el consumo de espacio durante la transmisión, pero no es favorable para la observación humana. En algunos casos, necesitamos serializarlo en una forma que los humanos puedan observar. Para ello, solo necesitamos cambiar de función.
func MarshalIndent(v any, prefix, indent string) ([]byte, error)func main() {
person := Person{
UserId: "1202",
Username: "jack",
Age: 19,
Address: "USA",
}
bytes, err := json.MarshalIndent(person, "", "\t")
if err != nil {
fmt.Println(err)
return
}
fmt.Println(string(bytes))
}La salida es la siguiente
{
"id": "1202",
"name": "jack",
"age": 19,
"address": "USA"
}Deserialización
Al deserializar, debe tenerse en cuenta que si la estructura tiene una etiqueta json, el nombre del campo se basa principalmente en la etiqueta json; de lo contrario, se basa en el nombre de la propiedad de la estructura.
func main() {
person := Person{}
jsonStr := "{\"id\":\"120\",\"name\":\"jack\",\"age\":18,\"address\":\"usa\"}\n"
err := json.Unmarshal([]byte(jsonStr), &person)
if err != nil {
fmt.Println(err)
return
}
fmt.Printf("%+v", person)
}Salida
{UserId:120 Username:jack Age:18 Address:usa}Protocol Buffers
Protocol es un lenguaje neutral, protocolo neutral, mecanismo de serialización de datos estructurados escalable de código abierto de Google en 2008. En comparación con los tres anteriores, es más ligero y más rápido al desempacar y empaquetar. Se usa principalmente en el campo de comunicación RPC. Para una explicación de Protobuf, puede visitar Protobuf.
Instalar dependencias
go get github.com/golang/protobuf/protoArchivo person.proto
syntax = "proto3";
option go_package = "./;person";
package proto;
enum Gender{
MAIL = 0;
FE_MAIL = 1;
}
message person {
string name = 1;
int32 age = 2;
Gender gender = 3;
}Después de generar el archivo
package main
import (
p "GoProject/src/proto"
"fmt"
"github.com/golang/protobuf/proto"
)
func main() {
person := p.Person{
Name: "wyh",
Age: 12,
Gender: p.Gender_FE_MAIL,
}
data, err := proto.Marshal(&person)//Serialización
if err != nil {
fmt.Println(err)
return
}
temp := &p.Person{}
fmt.Println("proto buffer len: ", len(data), "bytes:", data)
err = proto.Unmarshal(data, temp)//Deserialización
if err != nil {
fmt.Println(err)
return
}
fmt.Println(temp)
}Salida
proto buffer len: 9 bytes: [10 3 119 121 104 16 12 24 1]
name:"wyh" age:12 gender:FE_MAILSin embargo, normalmente no serializamos manualmente. El compilador protoc puede generar el código fuente en el idioma correspondiente según el archivo proto que hayamos definido.
