Skip to content

Enkoding dan Dekoding Encode Go

Di era internet saat ini, format data yang independen dari bahasa yang paling umum digunakan adalah xml, Yaml, json, protobuf. Go juga mendukung operasi terkait untuk format data ini. Berikut adalah tabel perbandingannya.

NamaXMLYAMLJSONProtocol Buffers
Struktur DataKompleksAgak SederhanaSederhanaAgak Kompleks
Cara PenyimpananTeksTeksTeksBiner
Ukuran PenyimpananBesarSedangSedangKecil
Efisiensi ParsingLambatSedangSedangCepat
Dukungan BahasaSangat BanyakBanyakSangat BanyakCukup Banyak
Tingkat Kesulitan PengembanganRumitAgak SederhanaSederhanaSederhana
Biaya PembelajaranRendahRendahRendahRendah
Lingkup PenerapanPertukaran DataFile KonfigurasiPertukaran DataPertukaran Data

TIP

Di Go, jika Anda ingin melakukan serialisasi dan deserialisasi pada struct, field harus diekspos, yaitu huruf pertama harus kapital.

Selain itu, TOML juga mulai populer, secara sintaksis mirip dengan perbaikan .ini. Jika tertarik, Anda dapat mempelajarinya di TOML: Tom's Obvious, Minimal Language.

XML

xml singkatan dari eXtensible Markup Language, adalah format untuk menyimpan data yang berasal dari tahun 1960-an, merupakan format data tertua di antara beberapa format data di atas. Format ini memiliki banyak kegunaan, termasuk transmisi jaringan, pertukaran data, file konfigurasi, penyimpanan data, dll. Namun seiring perkembangan zaman, format ini perlahan digantikan oleh bahasa markup baru.

Pertama, definisikan struct

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) // Serialisasi xml

func MarshalIndent(v any, prefix, indent string) ([]byte, error) // Format

func Unmarshal(data []byte, v any) error // Deserialisasi

Serialisasi

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))
}

Output

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

Deserialisasi

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
   }
}

Output

go
{UserId:120 Username:jack Age:18 Address:usa}

Namun, metode parsing xml tradisional sering memerlukan pembuatan struct baru, yang sangat merepotkan. Jika parsing struktur xml sederhana, masih bisa ditangani, tetapi jika menggunakan struktur yang kompleks, akan sangat memusingkan. Oleh karena itu, kebanyakan orang akan menggunakan library open source pihak ketiga etree untuk parsing xml. Jika tertarik, Anda dapat mempelajarinya sendiri: Go比较好用的解析 xml 文件的插件 etree - 掘金 (juejin.cn)

YML

Sintaks YAML mirip dengan bahasa pemrograman tingkat tinggi lainnya, dan dapat dengan mudah mengekspresikan data seperti list, map, skalar, dll. YAML menggunakan indentasi whitespace dan sangat bergantung pada fitur tampilan, sangat cocok untuk mengekspresikan atau mengedit struktur data, berbagai file konfigurasi. YML juga ada di banyak proyek dalam bentuk file konfigurasi, struktur kontennya lebih ringkas dan jelas. Go resmi tidak menyediakan dukungan untuk YML, kita perlu menggunakan package pihak ketiga.

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

Metode Utama

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

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

Siapkan struct terlebih dahulu

go
type Config struct {
   Database string `yaml:"database"`
   Url      string `yaml:"url"`
   Port     int    `yaml:"port"`
   Username string `yaml:"username"`
   Password string `yaml:"password"`
}

File konfigurasi

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

Serialisasi

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))
}

Output

yaml
database: oracle
url: localhost
port: 3326
username: root
password: "123456"

Namun karena yml sendiri memiliki sintaks indentasi yang ketat, jadi tidak ada masalah dengan format serialisasi.

Deserialisasi

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)
}

Output

{mysql 127.0.0.1 3306 root 123456}

JSON

json sering digunakan dalam komunikasi antarmuka dengan gaya Restful. Dibandingkan dengan xml, ukurannya lebih ringan dan biaya pembelajaran yang lebih rendah menjadikannya format pertukaran data utama di bidang web.

Di Go, package encoding/json menyediakan fungsi yang sesuai untuk melakukan serialisasi dan deserialisasi JSON. Fungsi utama yang digunakan adalah sebagai berikut.

go
func Marshal(v any) ([]byte, error) // Serialisasi objek Go ke string JSON

func Unmarshal(data []byte, v any) error // Deserialisasi string JSON ke objek Go

Pertama, definisikan struct

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

Serialisasi

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))
}

Hasil

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

Penamaan Ulang Field

Kita dapat mencapai efek penamaan ulang melalui tag struct.

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

Output saat ini

json
{ "id": "1202", "name": "jack", "age": 19, "address": "USA" }

Indentasi

Secara default, serialisasi tidak memiliki indentasi apa pun. Ini untuk mengurangi konsumsi ruang selama transmisi, tetapi ini tidak menguntungkan untuk pengamatan manusia. Dalam beberapa kasus, kita perlu mengubahnya menjadi bentuk yang dapat diamati oleh manusia. Untuk ini, cukup ganti fungsi.

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))
}

Output sebagai berikut

json
{
  "id": "1202",
  "name": "jack",
  "age": 19,
  "address": "USA"
}

Deserialisasi

Saat deserialisasi, perlu diperhatikan bahwa jika struct memiliki tag json, maka nama field akan mengutamakan tag json, jika tidak maka akan mengutamakan nama properti struct.

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)
}

Output

go
{UserId:120 Username:jack Age:18 Address:usa}

Protocol Buffers

Protocol adalah bahasa yang diopen source oleh Google pada tahun 2008, netral terhadap bahasa, netral terhadap protokol, mekanisme serialisasi data terstruktur yang dapat diperluas. Dibandingkan dengan ketiga format di atas, format ini lebih ringan, dan lebih cepat saat melakukan unpacking dan packing, banyak digunakan dalam bidang komunikasi RPC. Penjelasan tentang Protobuf dapat ditemukan di Protobuf.

Instal dependensi

go get github.com/golang/protobuf/proto

File 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;
}

Setelah menghasilkan file

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)// Serialisasi
  if err != nil {
    fmt.Println(err)
    return
  }
  temp := &p.Person{}
  fmt.Println("proto buffer len: ", len(data), "bytes:", data)
  err = proto.Unmarshal(data, temp)// Deserialisasi
  if err != nil {
    fmt.Println(err)
    return
  }
  fmt.Println(temp)
}

Output

proto buffer len:  9 bytes: [10 3 119 121 104 16 12 24 1]
name:"wyh"  age:12  gender:FE_MAIL

Namun biasanya kita tidak akan melakukan serialisasi secara manual, compiler protoc dapat menghasilkan kode sumber bahasa yang sesuai berdasarkan file proto yang telah kita definisikan.

Golang by www.golangdev.cn edit