Skip to content

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.

NombreXMLYAMLJSONProtocol Buffers
Estructura de datosComplejaMás simpleSimpleMás compleja
Modo de almacenamientoTextoTextoTextoBinario
Tamaño de almacenamientoGrandeMedianoMedianoPequeño
Eficiencia de análisisLentaMediaMediaRápida
Soporte de lenguajesMuchosMuchosMuchosVarios
Dificultad de desarrolloComplejoMás simpleSimpleSimple
Costo de aprendizajeBajoBajoBajoBajo
Ámbito de aplicaciónIntercambio de datosArchivo de configuraciónIntercambio de datosIntercambio 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

go
type Person struct {
   UserId   string `xml:"id"`
   Username string `xml:"name"`
   Age      int    `xml:"age"`
   Address  string `xml:"address"`
}
go
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ón

Serialización

go
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

xml
<Person>
        <id>120</id>
        <name>jack</name>
        <age>18</age>
        <address>usa</address>
</Person>

Deserialización

go
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

go
{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.

powershell
go get github.com/go-yaml/yaml

Métodos principales

go
func Marshal(in interface{}) (out []byte, err error) //Serialización

func Unmarshal(in []byte, out interface{}) (err error) //Deserialización

Primero, preparemos la estructura

go
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

yaml
database: mysql
url: 127.0.0.1
port: 3306
username: root
password: 123456

Serialización

go
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

yaml
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

go
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.

go
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 Go

Primero, definamos la estructura

go
type Person struct {
   UserId   string
   Username string
   Age      int
   Address  string
}

Serialización

go
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

json
{ "UserId": "120", "Username": "jack", "Age": 18, "Address": "usa" }

Renombramiento de campos

Podemos lograr el efecto de renombramiento a través de etiquetas de estructura.

go
type Person struct {
   UserId   string `json:"id"`
   Username string `json:"name"`
   Age      int    `json:"age"`
   Address  string `json:"address"`
}

Salida en este momento

json
{ "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.

go
func MarshalIndent(v any, prefix, indent string) ([]byte, error)
go
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

json
{
  "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.

go
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

go
{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/proto

Archivo person.proto

protobuf
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

go
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_MAIL

Sin 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.

Golang editado por www.golangdev.cn