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.
| Nama | XML | YAML | JSON | Protocol Buffers |
|---|---|---|---|---|
| Struktur Data | Kompleks | Agak Sederhana | Sederhana | Agak Kompleks |
| Cara Penyimpanan | Teks | Teks | Teks | Biner |
| Ukuran Penyimpanan | Besar | Sedang | Sedang | Kecil |
| Efisiensi Parsing | Lambat | Sedang | Sedang | Cepat |
| Dukungan Bahasa | Sangat Banyak | Banyak | Sangat Banyak | Cukup Banyak |
| Tingkat Kesulitan Pengembangan | Rumit | Agak Sederhana | Sederhana | Sederhana |
| Biaya Pembelajaran | Rendah | Rendah | Rendah | Rendah |
| Lingkup Penerapan | Pertukaran Data | File Konfigurasi | Pertukaran Data | Pertukaran 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
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) // Serialisasi xml
func MarshalIndent(v any, prefix, indent string) ([]byte, error) // Format
func Unmarshal(data []byte, v any) error // DeserialisasiSerialisasi
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
<Person>
<id>120</id>
<name>jack</name>
<age>18</age>
<address>usa</address>
</Person>Deserialisasi
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
{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.
go get github.com/go-yaml/yamlMetode Utama
func Marshal(in interface{}) (out []byte, err error) // Serialisasi
func Unmarshal(in []byte, out interface{}) (err error) // DeserialisasiSiapkan struct terlebih dahulu
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
database: mysql
url: 127.0.0.1
port: 3306
username: root
password: 123456Serialisasi
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
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
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.
func Marshal(v any) ([]byte, error) // Serialisasi objek Go ke string JSON
func Unmarshal(data []byte, v any) error // Deserialisasi string JSON ke objek GoPertama, definisikan struct
type Person struct {
UserId string
Username string
Age int
Address string
}Serialisasi
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
{ "UserId": "120", "Username": "jack", "Age": 18, "Address": "usa" }Penamaan Ulang Field
Kita dapat mencapai efek penamaan ulang melalui tag struct.
type Person struct {
UserId string `json:"id"`
Username string `json:"name"`
Age int `json:"age"`
Address string `json:"address"`
}Output saat ini
{ "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.
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))
}Output sebagai berikut
{
"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.
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
{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/protoFile 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;
}Setelah menghasilkan file
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_MAILNamun biasanya kita tidak akan melakukan serialisasi secara manual, compiler protoc dapat menghasilkan kode sumber bahasa yang sesuai berdasarkan file proto yang telah kita definisikan.
