Go 言語 encode エンコード・デコード
現在のインターネット時代において、最も一般的に使用される言語に依存しないデータ形式には xml、Yaml、json、protobuf があります。Go も同様にこれらのデータ形式の関連操作をサポートしています。以下は比較表です。
| 名称 | XML | YAML | JSON | Protocol Buffers |
|---|---|---|---|---|
| データ構造 | 複雑 | やや単純 | 単純 | やや複雑 |
| 保存方式 | テキスト | テキスト | テキスト | バイナリ |
| 保存サイズ | 大 | 中 | 中 | 小 |
| 解析効率 | 遅い | 中 | 中 | 速い |
| 言語サポート | 非常に多い | 多い | 非常に多い | 较多 |
| 開発難易度 | 煩雑 | やや単純 | 単純 | 単純 |
| 学習コスト | 低い | 低い | 低い | 低い |
| 適用範囲 | データ交換 | 設定ファイル | データ交換 | データ交換 |
TIP
Go で構造体のシリアライゼーションとデシリアライゼーションを行うには、フィールドは外部に公開されている必要があります。つまり、最初の文字を大文字にする必要があります。
また、TOML も徐々に普及し始めています。文法は .ini の改良版のようです。興味がある方は TOML:Tom's Obvious, Minimal Language をご覧ください。
XML
xml は eXtensible Markup Language の略で、データを保存するための形式です。20 世紀 60 年代に起源を持ち、上記のデータ形式の中で最も古いです。用途は非常に広く、ネットワーク転送、データ交換、設定ファイル、データストレージなどに使用できます。しかし、時代の移り変わりとともに、徐々に新しいマークアップ言語に置き換えられつつあります。
まず構造体を定義します。
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
Protocol Buffers は Google が 2008 年にオープンソース化した、言語中立、プロトコル中立、拡張可能な構造化データシリアライゼーションメカニズムです。上記の 3 つと比較してより軽量で、アンパケット化とパケット化の際により高速です。主に RPC 分野の通信などに使用されます。Protobuf に関する詳細は Protobuf をご覧ください。
依存関係をインストールします。
go get github.com/golang/protobuf/protoperson.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 ファイルに基づいて対応する言語のソースコードを生成します。
