Skip to content

Go لغة encode الترميز وفك الترميز

في عصر الإنترنت الحالي، صيغ البيانات الأكثر شيوعاً المستقلة عن اللغة هي xml، Yaml، json، protobuf، وتدعم Go أيضاً العمليات المتعلقة بهذه صيغ البيانات، فيما يلي جدول مقارنة.

الاسمXMLYAMLJSONProtocol Buffers
هيكل البياناتمعقدبسيط نسبياًبسيطمعقد نسبياً
طريقة الحفظنصنصنصثنائي
حجم الحفظكبيرمتوسطمتوسطصغير
كفاءة التحليلبطيءمتوسطمتوسطسريع
دعم اللغاتكثير جداًكثيركثير جداًكثير نسبياً
صعوبة التطويرمملبسيط نسبياًبسيطبسيط
تكلفة التعلممنخفضمنخفضمنخفضمنخفض
نطاق الاستخدامتبادل البياناتملفات التكوينتبادل البياناتتبادل البيانات

TIP

في Go، إذا كنت تريد إجراء تسلسل وإلغاء تسلسل للهياكل، يجب أن تكون الحقول مكشوفة للخارج، أي أن الحرف الأول كبير.

بالإضافة إلى ذلك، بدأ TOML يكتسب شعبية تدريجياً، وبنائه يشبه تحسين .ini، يمكنك زيارة TOML: لغة توم الواضحة دلالياً والحد الأدنى للتكوين للتعرف عليها.

XML

xml والمعروف أيضاً بـ eXtensible Markup Language، هو صيغة لتخزين البيانات، نشأ في الستينيات من القرن العشرين، وهو أقدم صيغ البيانات المذكورة أعلاه. استخدامه واسع جداً، يمكن استخدامه لنقل الشبكة، وتبادل البيانات، وملفات التكوين، وتخزين البيانات وغيرها. ولكن مع مرور الوقت، يتم استبداله تدريجياً بلغات ترميز جديدة.

أولاً قم بتعريف الهيكل

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

func MarshalIndent(v any, prefix, indent string) ([]byte, error) // تنسيق

func Unmarshal(data []byte, v any) error // إلغاء التسلسل

التسلسل

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

الإخراج

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

إلغاء التسلسل

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

الإخراج

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

لكن طريقة تحليل xml التقليدية غالباً ما تتطلب إنشاء هيكل جديد، وهذا يكون مملّاً جداً، وما نقوم بتحليله الآن هي هياكل xml بسيطة، وإذا استخدمنا هياكل معقدة، فسيكون ذلك صعباً جداً. لذلك نستخدم في معظم الأحيان مكتبة مفتوحة المصدر خارجية etree لتحليل xml، يمكنك التعرف عليها بنفسك: Go مكوّن جيد لتحليل ملفات xml etree - juejin.cn.

YML

بناء YAML مشابه للغات المتقدمة الأخرى، ويمكنه التعبير ببساطة عن القوائم، وجداول التجزئة، والكميات القياسية وغيرها من أشكال البيانات. يستخدم رموز المسافات البيضاء للمسافات البادئة ويعتمد كثيراً على المظهر، ومناسب جداً للتعبير عن أو تحرير هياكل البيانات، وملفات التكوين المختلفة، كما يوجد YML في العديد من المشاريع على شكل ملفات تكوين، وبنيته أكثر وضوحاً، وواضحة بوضوح. لم توفر Go رسمياً دعماً لـ YML، نحتاج لاستخدام حزمة خارجية.

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

الطرق الرئيسية

go
func Marshal(in interface{}) (out []byte, err error) // التسلسل

func Unmarshal(in []byte, out interface{}) (err error) // إلغاء التسلسل

أولاً قم بإعداد الهيكل

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

ملف التكوين

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

التسلسل

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

الإخراج

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

ولكن نظراً لأن yml نفسه يحتوي على بناء مسافات بادئة صارم، فلا توجد مشكلة في تنسيق التسلسل.

إلغاء التسلسل

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

الإخراج

{mysql 127.0.0.1 3306 root 123456}

JSON

يُستخدم json كثيراً في اتصالات واجهة نمط Restful، وحجمه أخف من xml، وتكلفة تعلمه منخفضة جعلته صيغة تبادل بيانات رئيسية في مجال web.

في Go، توفر الحزمة encoding/json الوظائف المقابلة لإجراء تسلسل وإلغاء تسلسل json، والوظائف الرئيسية المستخدمة هي كما يلي.

go
func Marshal(v any) ([]byte, error) // تحويل كائن Go إلى سلسلة json

func Unmarshal(data []byte, v any) error // تحويل سلسلة json إلى كائن Go

أولاً قم بتعريف الهيكل

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

التسلسل

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

النتيجة

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

إعادة تسمية الحقل

يمكننا تحقيق تأثير إعادة التسمية من خلال وسوم الهيكل.

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

الإخراج في هذه الحالة

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

المسافات البادئة

لا توجد مسافات بادئة افتراضياً عند التسلسل، وهذا لتقليل فقدان المساحة أثناء النقل، لكن هذا لا يساعد على الملاحظة البشرية، في بعض الحالات نحتاج إلى تسلسله بشكل يمكن للبشر ملاحظته. لذلك، نحتاج فقط لتغيير الوظيفة.

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

الإخراج كالتالي

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

إلغاء التسلسل

عند إلغاء التسلسل، يجب الانتباه، إذا كان الهيكل يحتوي على وسوم json، فاسم الحقل يُفضّل حسب وسم json، وإلا فحسب اسم خاصية الهيكل.

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

الإخراج

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

Protocol Buffers

بروتوكول هو آلية تسلسل بيانات هيكلية محايدة للغة ومحايدة للبروتوكول وقابلة للتوسيع، مفتوحة المصدر من جوجل في 2008. بالمقارنة مع الأنواع الثلاثة أعلاه، فهو أخف وزناً، وأسرع في التعبئة وإلغاء التعبئة، ويُستخدم كثيراً في مجال RPC للاتصالات ذات الصلة، لشرح Protobuf يمكنك زيارة Protobuf.

تثبيت التبعية

go get github.com/golang/protobuf/proto

ملف 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;
}

بعد إنشاء الملف

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)// التسلسل
  if err != nil {
    fmt.Println(err)
    return
  }
  temp := &p.Person{}
  fmt.Println("proto buffer len: ", len(data), "bytes:", data)
  err = proto.Unmarshal(data, temp)// إلغاء التسلسل
  if err != nil {
    fmt.Println(err)
    return
  }
  fmt.Println(temp)
}

الإخراج

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

لكننا عادة لا نقوم بالتسلسل يدوياً، فمترجم protoc يمكنه إنشاء الكود المصدري باللغة المقابلة بناءً على ملف proto الذي نحدده.

Golang تم تحريره بواسطة www.golangdev.cn