Skip to content

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.

İsimXMLYAMLJSONProtocol Buffers
Veri YapısıKarmaşıkDaha BasitBasitDaha Karmaşık
Saklama YöntemiMetinMetinMetinBinary
Saklama BoyutuBüyükOrtaOrtaKüçük
Ayrıştırma VerimliliğiYavaşOrtaOrtaHızlı
Dil DesteğiÇok FazlaFazlaÇok FazlaOldukça Fazla
Geliştirme ZorluğuKarmaşıkDaha BasitBasitBasit
Öğrenme MaliyetiDüşükDüşükDüşükDüşük
Kullanım AlanıVeri AlışverişiYapılandırma DosyasıVeri AlışverişiVeri 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

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

func MarshalIndent(v any, prefix, indent string) ([]byte, error) //Biçimlendirme

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

Serialize

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

Çıktı

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

Deserialize

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

Çıktı

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

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

Ana Metodlar

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

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

Öncelikle struct hazırlayalım

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

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

Serialize

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

Çıktı

yaml
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

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

Çı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.

go
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

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

Serialize

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

Sonuç

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

Alan Yeniden Adlandırma

Struct etiketleri kullanarak yeniden adlandırma efekti elde edebiliriz.

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

Bu durumda çıktı

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

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

Çıktı aşağıdaki gibidir

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

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

Çıktı

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

person.proto dosyası

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

Dosya oluşturulduktan sonra

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)//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_MAIL

Ancak genellikle manuel serialize işlemi yapmayız, protoc derleyicisi tanımladığımız proto dosyasına göre ilgili dilde kaynak kodu oluşturur.

Golang by www.golangdev.cn edit