What's the purpose of gob.Register method?

huangapple go评论166阅读模式
英文:

What's the purpose of gob.Register method?

问题

我已经阅读了(gob)的文档,我有一些问题:

现在我知道如何编码和解码结构体,就像这样:

func main() {
    s1 := &S{
        Field1: "Hello Gob",
        Field2: 999,
    }
    log.Println("Original value:", s1)
    buf := new(bytes.Buffer)
    err := gob.NewEncoder(buf).Encode(s1)
    if err != nil {
        log.Println("Encode:", err)
        return
    }

    s2 := &S{}
    err = gob.NewDecoder(buf).Decode(s2)
    if err != nil {
        log.Println("Decode:", err)
        return
    }
    log.Println("Decoded value:", s2)
}

但是我不知道这个方法gob.Register()的目的是什么,有人可以解释一下何时使用它以及为什么使用吗?

英文:

I have read the documentation of ( gob) and I have some problems :

Now I know how to encode structure and decode like that:

func main() {
	s1 := &S{
		Field1: "Hello Gob",
		Field2: 999,
	}
	log.Println("Original value:", s1)
	buf := new(bytes.Buffer)
	err := gob.NewEncoder(buf).Encode(s1)
	if err != nil {
		log.Println("Encode:", err)
		return
	}

	s2 := &S{}
	err = gob.NewDecoder(buf).Decode(s2)
	if err != nil {
		log.Println("Decode:", err)
		return
	}
    log.Println("Decoded value:", s2)
}

But I don't know the purpose of this method gob.Register() can someone explain to me when to use it and why?

答案1

得分: 14

如果你只处理具体类型(结构体),那么实际上不需要进行注册。但是,一旦你处理接口类型,就必须先注册你的具体类型。

例如,假设我们有以下结构体和接口(结构体实现了接口):

type Getter interface {
    Get() string
}

type Foo struct {
    Bar string
}

func (f Foo) Get() string {
    return f.Bar
}

要将 Foo 作为 Getter 类型通过 gob 进行发送和解码,我们必须首先调用:

gob.Register(Foo{})

因此,流程如下:

// 初始化和注册
buf := bytes.NewBuffer(nil)
gob.Register(Foo{})

// 创建一个 Foo 的 Getter
g := Getter(Foo{"wazzup"})

// 编码
enc := gob.NewEncoder(buf)
enc.Encode(&g)

// 解码
dec := gob.NewDecoder(buf)
var gg Getter
if err := dec.Decode(&gg); err != nil {
    panic(err)
}

现在尝试移除 Register,这将无法工作,因为 gob 不知道如何将数据映射回其适当的类型。

英文:

If you're dealing with concrete types (structs) only, you don't really need it. Once you're dealing with interfaces you must register your concrete type first.

For example, let's assume we have these struct and interface (the struct implements the interface):

type Getter interface {
    Get() string
}


type Foo struct {
    Bar string
}

func (f Foo)Get() string {
    return f.Bar
}

To send a Foo over gob as a Getter and decode it back, we must first call

gob.Register(Foo{})

So the flow would be:

// init and register
buf := bytes.NewBuffer(nil)
gob.Register(Foo{})    


// create a getter of Foo
g := Getter(Foo{"wazzup"})
 
// encode
enc := gob.NewEncoder(buf)
enc.Encode(&g)

// decode
dec := gob.NewDecoder(buf)
var gg Getter
if err := dec.Decode(&gg); err != nil {
    panic(err)
}

Now try removing the Register and this won't work because gob wouldn't know how to map things back to their appropriate type.

答案2

得分: 0

根据http://golang.org/pkg/encoding/gob/#Register所说:

只有作为接口值实现进行传输的类型需要进行注册。

所以在你的演示中不需要进行注册。

英文:

As http://golang.org/pkg/encoding/gob/#Register said:

> Only types that will be transferred as implementations of interface
> values need to be registered.

So it doesn't needed by your demo.

答案3

得分: 0

如果你想对一个map[string]interface{}进行编码/解码操作,由于map的字段被封装为接口类型,我们需要在操作之前注册具体的类型。

package main

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

type SomeStruct struct {
	Text string
}

func main() {
	var bytes bytes.Buffer

	// 移除其中一个注册语句,解码过程将会产生错误
	gob.Register(SomeStruct{})
	gob.Register([]interface{}{})
	gob.Register([]SomeStruct{})
    gob.Register(map[string]SomeStruct{})

	writer := gob.NewEncoder(&bytes)

	err := writer.Encode(map[string]interface{}{
		"SomeStruct":       SomeStruct{"Halo"},
		"SomeSlice":        []interface{}{},
		"SomeSliceStruct":  []SomeStruct{{Text: "SomeText"}},
        "SomeMapStruct":    map[string]SomeStruct{"S": {"Test"}},
	})
	if err != nil {
		log.Fatalf("编码过程出错:%v\n", err)
		return
	}

	reader := gob.NewDecoder(&bytes)
	var aMap map[string]interface{}
	err = reader.Decode(&aMap)
	if err != nil {
		log.Fatalf("解码过程出错:%v\n", err)
		return
	}

	fmt.Printf("解码成功:%+v\n", aMap)
}
英文:

If you want to encode / decode a map[string]interface{}, since the field of the map is enclosed as interface type, then we need to register the specific type before.


package main

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

type SomeStruct struct {
	Text string
}

func main() {
	var bytes bytes.Buffer

	// Remove one of these, then the decoding will produce error
	gob.Register(SomeStruct{})
	gob.Register([]interface{}{})
	gob.Register([]SomeStruct{})
    gob.Register(map[string]SomeStruct{})

	writer := gob.NewEncoder(&bytes)

	err := writer.Encode(map[string]interface{}{
		"SomeStruct": SomeStruct{"Halo"},
		"SomeSlice":  []interface{}{},
		"SomeSliceStruct": []SomeStruct{
			{
				Text: "SomeText",
			},
		},
        "SomeMapStruct": map[string]SomeStruct{
			"S": {"Test"},
		},
	})
	if err != nil {
		log.Fatalf("Error on encode process: %v\n", err)
		return
	}

	reader := gob.NewDecoder(&bytes)
	var aMap map[string]interface{}
	err = reader.Decode(&aMap)
	if err != nil {
		log.Fatalf("Error on decode process: %v\n", err)
		return
	}

	fmt.Printf("Decode is successful: %+v\n", aMap)
}

huangapple
  • 本文由 发表于 2015年9月20日 15:26:56
  • 转载请务必保留本文链接:https://go.coder-hub.com/32676898.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定