Go Dili encode Kodlama ve Kod Çözme
Günümüz internet çağında, dilden bağımsız en yaygın veri formatları xml, Yaml, json ve protobuf'tur. Go da bu veri formatlarıyla ilgili işlemleri destekler. Aşağıda karşılaştırma tablosu verilmiştir.
| İsim | XML | YAML | JSON | Protocol Buffers |
|---|---|---|---|---|
| Veri Yapısı | Karmaşık | Daha Basit | Basit | Daha Karmaşık |
| Saklama Yöntemi | Metin | Metin | Metin | Binary |
| Saklama Boyutu | Büyük | Orta | Orta | Küçük |
| Ayrıştırma Verimliliği | Yavaş | Orta | Orta | Hızlı |
| Dil Desteği | Çok Fazla | Fazla | Çok Fazla | Oldukça Fazla |
| Geliştirme Zorluğu | Karmaşık | Daha Basit | Basit | Basit |
| Öğrenme Maliyeti | Düşük | Düşük | Düşük | Düşük |
| Kullanım Alanı | Veri Alışverişi | Yapılandırma Dosyası | Veri Alışverişi | Veri Alışverişi |
TIP
Go'da bir struct'ı serialize ve deserialize etmek istiyorsanız, alanların dışa açık olması gerekir, yani ilk harf büyük olmalıdır.
Ayrıca, TOML da popülerleşmeye başladı, sözdizimi açısından .ini dosyalarının geliştirilmiş bir versiyonu gibidir. Merak edenler TOML: Tom's Obvious, Minimal Language sayfasına göz atabilir.
XML
xml yani eXtensible Markup Language, veri depolamak için kullanılan bir formattır. 20. yüzyılın 60'lı yıllarında ortaya çıkmıştır ve yukarıdaki veri formatları arasında en eski olanıdır. Kullanım alanı oldukça geniştir; ağ iletişimi, veri alışverişi, yapılandırma dosyaları, veri depolama gibi alanlarda kullanılabilir. Ancak zamanın değişmesiyle birlikte, yerini yeni işaretleme dillerine bırakmaktadır.
Öncelikle struct tanımlayalım
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) //xml serialize
func MarshalIndent(v any, prefix, indent string) ([]byte, error) //Biçimlendirme
func Unmarshal(data []byte, v any) error //DeserializeSerialize
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))
}Çıktı
<Person>
<id>120</id>
<name>jack</name>
<age>18</age>
<address>usa</address>
</Person>Deserialize
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
}
}Çıktı
{UserId:120 Username:jack Age:18 Address:usa}Ancak geleneksel xml ayrıştırma yöntemi genellikle struct oluşturmeyi gerektirir, bu da oldukça karmaşık olabilir. Günümüzde genellikle basit xml yapıları ayrıştırılır, ancak karmaşık yapılar kullanıldığında bu sorun yaratabilir. Bu nedenle çoğu zaman xml'i ayrıştırmak için etree adlı üçüncü taraf açık kaynak kütüphaneyi kullanırız. Merak edenler şunu inceleyebilir: Go için kullanışlı xml ayrıştırma eklentisi etree.
YML
YAML'ın sözdizimi diğer yüksek seviye dillere benzer ve liste, hash tablosu, skaler gibi veri tiplerini basitçe ifade edebilir. Boşluk karakterleriyle girintileme kullanır ve görünüşe dayalı özelliklere büyük ölçüde güvenir. Bu nedenle özellikle veri yapılarını ifade etmek veya düzenlemek, çeşitli yapılandırma dosyaları için oldukça uygundur. YML ayrıca birçok projede yapılandırma dosyası olarak da bulunur ve içerik yapısı daha öz ve anlaşılırdır. Go resmi olarak YML için destek sağlamaz, bu nedenle üçüncü taraf paket kullanmamız gerekir.
go get github.com/go-yaml/yamlAna Metodlar
func Marshal(in interface{}) (out []byte, err error) //Serialize
func Unmarshal(in []byte, out interface{}) (err error) //DeserializeÖncelikle struct hazırlayalım
type Config struct {
Database string `yaml:"database"`
Url string `yaml:"url"`
Port int `yaml:"port"`
Username string `yaml:"username"`
Password string `yaml:"password"`
}Yapılandırma dosyası
database: mysql
url: 127.0.0.1
port: 3306
username: root
password: 123456Serialize
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))
}Çıktı
database: oracle
url: localhost
port: 3326
username: root
password: "123456"yml'in kendisi katı girinti sözdizimine sahip olduğundan, serialize biçimlendirme sorunu da yoktur.
Deserialize
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)
}Çıktı
{mysql 127.0.0.1 3306 root 123456}JSON
json, Restful tarzı arayüz iletişimde sıkça kullanılır. xml'e kıyasla daha hafif olması ve düşük öğrenme maliyeti sayesinde web alanında ana akım veri alışverişi formatı haline gelmiştir.
Go'da encoding/json paketi json serialize ve deserialize işlemleri için ilgili fonksiyonları sağlar. Başlıca kullanılan fonksiyonlar şunlardır.
func Marshal(v any) ([]byte, error) //Go objesini json string'e serialize eder
func Unmarshal(data []byte, v any) error //Json string'i Go objesine deserialize ederÖncelikle struct tanımlayalım
type Person struct {
UserId string
Username string
Age int
Address string
}Serialize
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))
}Sonuç
{ "UserId": "120", "Username": "jack", "Age": 18, "Address": "usa" }Alan Yeniden Adlandırma
Struct etiketleri kullanarak yeniden adlandırma efekti elde edebiliriz.
type Person struct {
UserId string `json:"id"`
Username string `json:"name"`
Age int `json:"age"`
Address string `json:"address"`
}Bu durumda çıktı
{ "id": "1202", "name": "jack", "age": 19, "address": "USA" }Girinti
Serialize işlemi sırasında varsayılan olarak hiçbir girinti yoktur, bu iletim sırasında alan tasarrufu sağlamak içindir, ancak bu insan gözüyle incelemeyi kolaylaştırmaz. Bazı durumlarda insan tarafından okunabilir formata serialize etmemiz gerekebilir. Bunun için sadece fonksiyonu değiştirmemiz yeterlidir.
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))
}Çıktı aşağıdaki gibidir
{
"id": "1202",
"name": "jack",
"age": 19,
"address": "USA"
}Deserialize
Deserialize işlemi sırasında, eğer struct'ta json etiketi varsa, alan adı öncelikle json etiketine göre belirlenir, aksi takdirde struct özellik adına göre belirlenir.
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)
}Çıktı
{UserId:120 Username:jack Age:18 Address:usa}Protocol Buffers
Protocol, Google tarafından 2008 yılında açık kaynak yapılan, dil bağımsız, protokol bağımsız, genişletilebilir yapılandırılmış veri serialize mekanizmasıdır. Yukarıdaki üç formata kıyasla daha hafiftir ve paket açma/kapama işlemleri daha hızlıdır. Çoğunlukla RPC alanında iletişim için kullanılır. Protobuf hakkında daha fazla bilgi için Protobuf sayfasına bakabilirsiniz.
Bağımlılıkları yükle
go get github.com/golang/protobuf/protoperson.proto dosyası
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;
}Dosya oluşturulduktan sonra
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)//Serialize
if err != nil {
fmt.Println(err)
return
}
temp := &p.Person{}
fmt.Println("proto buffer len: ", len(data), "bytes:", data)
err = proto.Unmarshal(data, temp)//Deserialize
if err != nil {
fmt.Println(err)
return
}
fmt.Println(temp)
}Çıktı
proto buffer len: 9 bytes: [10 3 119 121 104 16 12 24 1]
name:"wyh" age:12 gender:FE_MAILAncak genellikle manuel serialize işlemi yapmayız, protoc derleyicisi tanımladığımız proto dosyasına göre ilgili dilde kaynak kodu oluşturur.
