ホームページ  >  記事  >  バックエンド開発  >  golangのシリアル化メソッドは何ですか?

golangのシリアル化メソッドは何ですか?

青灯夜游
青灯夜游オリジナル
2023-01-04 19:33:284016ブラウズ

Golang のシリアル化メソッドには次のものが含まれます: 1. Gob パッケージを使用して gob ストリームを管理します。Gob は型にバインドされています。多かれ少なかれ存在することが判明した場合は、その型に従って埋められるか切り詰められます。注文。 2. json パッケージを使用すると、RFC 7159 で定義されている JSON エンコードとデコードを実装できます。シリアル化プロセス中に、構造体のメンバーが小文字の場合、エラーが発生します。 3. Binary パッケージを使用すると、数値とバイト列の間の簡単な変換と、バリアントのエンコードとデコードを実現できます。 4. protobuf プロトコルを使用します。

golangのシリアル化メソッドは何ですか?

このチュートリアルの動作環境: Windows 7 システム、GO バージョン 1.18、Dell G3 コンピューター。

プログラミング プロセスでは、データ オブジェクトをネットワーク経由で送信したり、データ オブジェクトをファイルに保存したりするという問題に常に遭遇する必要があります。これには、エンコードとデコードのアクションが必要です。

現在、json、XML、Gob、Google Protocol Buffer など、多くのエンコード形式があります。Go 言語では、この方法でデータをエンコードおよびデコードするにはどうすればよいでしょうか?

シリアル化と逆シリアル化の定義

シリアル化 (シリアル化) は、オブジェクトの状態情報を保存または送信できる形式に変換することです。のプロセス。シリアル化中、オブジェクトは現在の状態を一時ストレージまたは永続ストレージに書き込みます。

逆に、記憶域から変数を再読み取りしてオブジェクトを再作成することは、逆シリアル化です。

Go 言語では、encoding パッケージは、この種のシリアル化エンコードおよびデコードの問題を処理するために特別に設計されています。

シリアル化メソッド – Gob

gob パッケージ管理 gob ストリーム – エンコーダー (送信者) とデコーダー 交換されるバイナリ値(受信機)間。一般的な用途は、「net/rpc」パッケージで使用される gobs ストリームなど、リモート プロシージャ コール (RPC) のパラメータと結果を転送することです。

詳細については、ドキュメントを参照してください: https://docs.studygolang.com/pkg/encoding/gob/

彼の公式 Web サイトには例が記載されています:

package main

import (
	"bytes"
	"encoding/gob"
	"fmt"
	"log"
)

type P struct {
	X, Y, Z int
	Name    string
}

type Q struct {
	X, Y *int32
	Name string
}

// This example shows the basic usage of the package: Create an encoder,
// transmit some values, receive them with a decoder.
func main() {
	// Initialize the encoder and decoder. Normally enc and dec would be
	// bound to network connections and the encoder and decoder would
	// run in different processes.
	var network bytes.Buffer        // Stand-in for a network connection  //Buffer是具有Read和Write方法的可变大小的字节缓冲区。
	enc := gob.NewEncoder(&network) // Will write to network.
	dec := gob.NewDecoder(&network) // Will read from network.

	// Encode (send) some values.
	err := enc.Encode(P{3, 4, 5, "Pythagoras"})
	if err != nil {
		log.Fatal("encode error:", err)
	}
	err = enc.Encode(P{1782, 1841, 1922, "Treehouse"})
	if err != nil {
		log.Fatal("encode error:", err)
	}

	// Decode (receive) and print the values.
	var q Q
	err = dec.Decode(&q)
	if err != nil {
		log.Fatal("decode error 1:", err)
	}
	fmt.Printf("%q: {%d, %d}\n", q.Name, *q.X, *q.Y)
	err = dec.Decode(&q)
	if err != nil {
		log.Fatal("decode error 2:", err)
	}
	fmt.Printf("%q: {%d, %d}\n", q.Name, *q.X, *q.Y)

}

Run 結果は次のようになります:

"Pythagoras": {3, 4}
"Treehouse": {1782, 1841}

個人的には、この例は非常に良いと思います。構造体 PQ が異なっており、Q には Z 変数が欠落していることがわかります。

ただし、デコード時に解析することは可能です。これは、gob を使用する場合、型に従ってバインドされていることを示しています。多かれ少なかれ存在することが判明した場合は、順序に基づいてパディングまたは切り詰めます。

次に、エンコード方法について詳しく説明します:

1. bytes.Buffer Type

まず、シリアル化する必要がある構造を受け入れるために bytes.Buffer 型を定義する必要があります。この型は次のようになります:

// A Buffer is a variable-sized buffer of bytes with Read and Write methods.(Buffer是具有Read和Write方法的可变大小的字节缓冲区)
// The zero value for Buffer is an empty buffer ready to use.
type Buffer struct {
	buf      []byte // contents are the bytes buf[off : len(buf)]
	off      int    // read at &buf[off], write at &buf[len(buf)]
	lastRead readOp // last read operation, so that Unread* can work correctly.
}

上記の例を使用すると、次のことができます。出力は次のとおりです:

"Pythagoras": {3, 4} ==>
{[42 255 129 3 1 1 1 80 1 255 130 0 1 4 1 1 88 1 4 0 1 1 89 1 4 0 1 1 90 1 4 0 1 4 78 97 109 101 1 12 0 0 0 21 255 130 1 6 1 8 1 10 1 10 80 121 116 104 97 103 111 114 97 115 0] 0 0}

Buffer では、これが 2 進数 (1 バイトは 8 ビット、最大 255) であることがわかります。

2. エンコード エンコード後、

、エンコードしてシリアル化する必要がある構造をエンコードします:

enc := gob.NewEncoder(&network) // Will write to network.
// Encode (send) some values.
if err := enc.Encode(P{3, 4, 5, "Pythagoras"}); err != nil {
	log.Fatal("encode error:", err)
}

ここで、最初に取得するのはです。 *Encoder オブジェクト。オブジェクトを取得した後、*Encoder オブジェクトのメソッド Encode を使用してエンコードします。

ここで注意していただきたいのは、Encode ネットワークプログラミングであれば、実際にはソケット送信操作を行わずに直接相手にメッセージを送信することができます。

例: srever 側にコードがあります:

func main() {
	l, err := net.Listen("tcp", "127.0.0.1:8000")  //监听端口
	if err != nil {
		log.Fatal("net Listen() error is ", err)
	}

	p := P{
		1, 2, 3,
		"name"}

	conn, err := l.Accept()
	if err != nil {
		log.Fatal("net Accept() error is ", err)
	}
	defer func() { _ = conn.Close() }()
	//参数是conn 时,即可发出
	enc := gob.NewEncoder(conn)
	if err = enc.Encode(p); err != nil {  //发生结构体数据
		log.Fatal("enc Encode() error is ", err)
	}
}

クライアント側にコードがあります:

func main() {
	conn,err := net.Dial("tcp","127.0.0.1:8000")
	if err != nil {
		log.Fatal("net Dial() error is ", err)
	}
	defer func() { _ = conn.Close() }()
	/**
	type Q struct {
		X, Y int
		Name string
	}
	 */
	var q Q
	dec := gob.NewDecoder(conn)
	if err = dec.Decode(&q); err != nil {
		log.Fatal("enc Encode() error is ", err)
	}
	fmt.Println(q)
}

出力:

{1 2 name}

3. デコード デコード

#最後に、デコードする手順は次のとおりです。

# シーケンス -json

json パッケージは、

RFC 7159

で定義されている JSON エンコードとデコードを実装します。 JSON 値と Go 値の間のマッピングについては、Marshal 関数と Unmarshal 関数のドキュメントで説明されています。 このパッケージの概要については、「JSON と Go」を参照してください: https://www.php.cn/link/241200d15bc67211b50bd10815259e58json/例は次のとおりです:

dec := gob.NewDecoder(&network) // Will read from network.
if err = dec.Decode(&q);err != nil {
	log.Fatal("decode error 2:", err)
}

注意

シリアル化プロセス中に、構造体のメンバーが小文字の場合、エラーが発生します。 上記の 2 つのメソッドはこのような結果を生成します

json シリアル化を例として、小文字の場合に結果がどのようになるかを見てみましょう:

type Message struct {
	QQ      string
	Address string
}

type Student struct {
	Id   uint64 `json:"id"` //可以保证json字段按照规定的字段转义,而不是输出 Id
	Age  uint64 `json:"age"`
	Data []Message
}

func main() {
	m1 := Message{QQ: "123", Address: "beijing"}
	m2 := Message{QQ: "456", Address: "beijing"}
	s1 := Student{3, 19, append([]Message{}, m1, m2)}
	var buf []byte
	var err error

	if buf, err = json.Marshal(s1); err != nil {
		log.Fatal("json marshal error:", err)
	}

	fmt.Println(string(buf))

	var s2 Student
	if err = json.Unmarshal(buf, &s2); err != nil {
		log.Fatal("json unmarshal error:", err)
	}
	fmt.Println(s2)
}
//输出:
//{"id":3,"age":19,"Data":[{"QQ":"123","Address":"beijing"},{"QQ":"456","Address":"beijing"}]}
//{3 19 [{123 beijing} {456 beijing}]}

出力: <pre class="brush:php;toolbar:false;">package main import ( &quot;encoding/json&quot; &quot;fmt&quot; &quot;log&quot; ) type Message struct { qq string address string } type Student struct { Id uint64 `json:&quot;id&quot;` //可以保证json字段按照规定的字段转义,而不是输出 Id Age uint64 `json:&quot;age&quot;` Data []Message } func main() { m1 := Message{&quot;123&quot;, &quot;beijing&quot;} m2 := Message{&quot;456&quot;, &quot;beijing&quot;} s1 := Student{3, 19, append([]Message{}, m1, m2)} var buf []byte var err error if buf, err = json.Marshal(s1); err != nil { log.Fatal(&quot;json marshal error:&quot;, err) } fmt.Println(string(buf)) var s2 Student if err = json.Unmarshal(buf, &amp;s2); err != nil { log.Fatal(&quot;json unmarshal error:&quot;, err) } fmt.Println(s2) }</pre>小文字部分はシリアル化されない、つまり null 値になることがわかります。

これはエラーを報告しませんが、明らかに私たちが望んでいる結果ではありません。

エラー レポート: gob: type xxx にはエクスポートされたフィールドがありません

エラー レポートの例を見てみましょう:
{"id":3,"age":19,"Data":[{},{}]}
{3 19 [{ } { }]}
このコードはエラーを報告します:

type Message struct {
	qq      string
	address string
}

type Student struct {
	Id   uint64 `json:"id"` //可以保证json字段按照规定的字段转义,而不是输出 Id
	Age  uint64 `json:"age"`
	Data []Message
}

func main() {
	m1 := Message{"123", "beijing"}
	m2 := Message{"456", "beijing"}
	s1 := Student{3, 19, append([]Message{}, m1, m2)}

	var buf bytes.Buffer
	enc := gob.NewEncoder(&buf)
	if err := enc.Encode(s1); err != nil {
		log.Fatal("encode error:", err) //报错
	}
	fmt.Println(string(buf.Bytes()))
}

構造では大文字と小文字が区別されることを思い出させます。 ! !

序列化方式–Binary

Binary 包实现 数字字节 序列之间的简单转换以及varint的编码和解码。

通过读取和写入固定大小的值来转换数字。 固定大小的值可以是固定大小的算术类型(bool,int8,uint8,int16,float32,complex64等),也可以是仅包含固定大小值的数组或结构体。详情可参考:https://www.php.cn/link/241200d15bc67211b50bd10815259e58binary/#Write

示例:

package main

import (
	"bytes"
	"encoding/binary"
	"fmt"
)

func main() {
	buf := new(bytes.Buffer)
	var pi int64 = 255

	err := binary.Write(buf, binary.LittleEndian, pi)
	if err != nil {
		fmt.Println("binary.Write failed:", err)
	}
	fmt.Println( buf.Bytes())
}
//输出:
[255 0 0 0 0 0 0 0]

这里需要注意:如果序列化的类型是 int 类型的话,将会报错:

binary.Write failed: binary.Write: invalid type int

而且,序列化的值是空的。

这是由于,他在前面已经解释清楚了,只能序列化固定大小的类型(bool,int8,uint8,int16,float32,complex64…),或者是结构体和固定大小的数组。

其他序列化方法

当然,go语言还有其他的序列化方法,如 protobuf 协议,参考:https://geektutu.com/post/quick-go-protobuf.html

【相关推荐:Go视频教程编程教学

以上がgolangのシリアル化メソッドは何ですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。