Go لغة encode الترميز وفك الترميز
في عصر الإنترنت الحالي، صيغ البيانات الأكثر شيوعاً المستقلة عن اللغة هي xml، Yaml، json، protobuf، وتدعم Go أيضاً العمليات المتعلقة بهذه صيغ البيانات، فيما يلي جدول مقارنة.
| الاسم | XML | YAML | JSON | Protocol Buffers |
|---|---|---|---|---|
| هيكل البيانات | معقد | بسيط نسبياً | بسيط | معقد نسبياً |
| طريقة الحفظ | نص | نص | نص | ثنائي |
| حجم الحفظ | كبير | متوسط | متوسط | صغير |
| كفاءة التحليل | بطيء | متوسط | متوسط | سريع |
| دعم اللغات | كثير جداً | كثير | كثير جداً | كثير نسبياً |
| صعوبة التطوير | ممل | بسيط نسبياً | بسيط | بسيط |
| تكلفة التعلم | منخفض | منخفض | منخفض | منخفض |
| نطاق الاستخدام | تبادل البيانات | ملفات التكوين | تبادل البيانات | تبادل البيانات |
TIP
في Go، إذا كنت تريد إجراء تسلسل وإلغاء تسلسل للهياكل، يجب أن تكون الحقول مكشوفة للخارج، أي أن الحرف الأول كبير.
بالإضافة إلى ذلك، بدأ TOML يكتسب شعبية تدريجياً، وبنائه يشبه تحسين .ini، يمكنك زيارة TOML: لغة توم الواضحة دلالياً والحد الأدنى للتكوين للتعرف عليها.
XML
xml والمعروف أيضاً بـ eXtensible Markup Language، هو صيغة لتخزين البيانات، نشأ في الستينيات من القرن العشرين، وهو أقدم صيغ البيانات المذكورة أعلاه. استخدامه واسع جداً، يمكن استخدامه لنقل الشبكة، وتبادل البيانات، وملفات التكوين، وتخزين البيانات وغيرها. ولكن مع مرور الوقت، يتم استبداله تدريجياً بلغات ترميز جديدة.
أولاً قم بتعريف الهيكل
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
func MarshalIndent(v any, prefix, indent string) ([]byte, error) // تنسيق
func Unmarshal(data []byte, v any) error // إلغاء التسلسلالتسلسل
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))
}الإخراج
<Person>
<id>120</id>
<name>jack</name>
<age>18</age>
<address>usa</address>
</Person>إلغاء التسلسل
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
}
}الإخراج
{UserId:120 Username:jack Age:18 Address:usa}لكن طريقة تحليل xml التقليدية غالباً ما تتطلب إنشاء هيكل جديد، وهذا يكون مملّاً جداً، وما نقوم بتحليله الآن هي هياكل xml بسيطة، وإذا استخدمنا هياكل معقدة، فسيكون ذلك صعباً جداً. لذلك نستخدم في معظم الأحيان مكتبة مفتوحة المصدر خارجية etree لتحليل xml، يمكنك التعرف عليها بنفسك: Go مكوّن جيد لتحليل ملفات xml etree - juejin.cn.
YML
بناء YAML مشابه للغات المتقدمة الأخرى، ويمكنه التعبير ببساطة عن القوائم، وجداول التجزئة، والكميات القياسية وغيرها من أشكال البيانات. يستخدم رموز المسافات البيضاء للمسافات البادئة ويعتمد كثيراً على المظهر، ومناسب جداً للتعبير عن أو تحرير هياكل البيانات، وملفات التكوين المختلفة، كما يوجد YML في العديد من المشاريع على شكل ملفات تكوين، وبنيته أكثر وضوحاً، وواضحة بوضوح. لم توفر Go رسمياً دعماً لـ YML، نحتاج لاستخدام حزمة خارجية.
go get github.com/go-yaml/yamlالطرق الرئيسية
func Marshal(in interface{}) (out []byte, err error) // التسلسل
func Unmarshal(in []byte, out interface{}) (err error) // إلغاء التسلسلأولاً قم بإعداد الهيكل
type Config struct {
Database string `yaml:"database"`
Url string `yaml:"url"`
Port int `yaml:"port"`
Username string `yaml:"username"`
Password string `yaml:"password"`
}ملف التكوين
database: mysql
url: 127.0.0.1
port: 3306
username: root
password: 123456التسلسل
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))
}الإخراج
database: oracle
url: localhost
port: 3326
username: root
password: "123456"ولكن نظراً لأن yml نفسه يحتوي على بناء مسافات بادئة صارم، فلا توجد مشكلة في تنسيق التسلسل.
إلغاء التسلسل
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، والوظائف الرئيسية المستخدمة هي كما يلي.
func Marshal(v any) ([]byte, error) // تحويل كائن Go إلى سلسلة json
func Unmarshal(data []byte, v any) error // تحويل سلسلة json إلى كائن Goأولاً قم بتعريف الهيكل
type Person struct {
UserId string
Username string
Age int
Address string
}التسلسل
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))
}النتيجة
{ "UserId": "120", "Username": "jack", "Age": 18, "Address": "usa" }إعادة تسمية الحقل
يمكننا تحقيق تأثير إعادة التسمية من خلال وسوم الهيكل.
type Person struct {
UserId string `json:"id"`
Username string `json:"name"`
Age int `json:"age"`
Address string `json:"address"`
}الإخراج في هذه الحالة
{ "id": "1202", "name": "jack", "age": 19, "address": "USA" }المسافات البادئة
لا توجد مسافات بادئة افتراضياً عند التسلسل، وهذا لتقليل فقدان المساحة أثناء النقل، لكن هذا لا يساعد على الملاحظة البشرية، في بعض الحالات نحتاج إلى تسلسله بشكل يمكن للبشر ملاحظته. لذلك، نحتاج فقط لتغيير الوظيفة.
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))
}الإخراج كالتالي
{
"id": "1202",
"name": "jack",
"age": 19,
"address": "USA"
}إلغاء التسلسل
عند إلغاء التسلسل، يجب الانتباه، إذا كان الهيكل يحتوي على وسوم json، فاسم الحقل يُفضّل حسب وسم json، وإلا فحسب اسم خاصية الهيكل.
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)
}الإخراج
{UserId:120 Username:jack Age:18 Address:usa}Protocol Buffers
بروتوكول هو آلية تسلسل بيانات هيكلية محايدة للغة ومحايدة للبروتوكول وقابلة للتوسيع، مفتوحة المصدر من جوجل في 2008. بالمقارنة مع الأنواع الثلاثة أعلاه، فهو أخف وزناً، وأسرع في التعبئة وإلغاء التعبئة، ويُستخدم كثيراً في مجال RPC للاتصالات ذات الصلة، لشرح Protobuf يمكنك زيارة Protobuf.
تثبيت التبعية
go get github.com/golang/protobuf/protoملف 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;
}بعد إنشاء الملف
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 الذي نحدده.
