我正在使用gob将结构序列化到磁盘。有问题的结构包含一个接口字段,因此具体类型需要使用进行注册gob.Register(...)
。
这里的难题是,进行灌装的图书馆应忽略所使用的混凝土类型。我希望即使调用者定义了自己的接口实现,也可以进行序列化。
我可以通过动态注册类型来成功编码数据(请参见下面的简单示例),但是在尝试重新读取数据时,gob拒绝接受未注册的类型。它令人沮丧,因为感觉好像所有数据都在那里-
main.UpperCaseTransformation
如果gob 标记为这样的结构,为什么不将它作为结构拆包呢?
package main
import (
"encoding/gob"
"fmt"
"os"
"strings"
)
type Transformation interface {
Transform(s string) string
}
type TextTransformation struct {
BaseString string
Transformation Transformation
}
type UpperCaseTransformation struct{}
func (UpperCaseTransformation) Transform(s string) string {
return strings.ToUpper(s)
}
func panicOnError(err error) {
if err != nil {
panic(err)
}
}
// Execute this twice to see the problem (it will tidy up files)
func main() {
file := os.TempDir() + "/so-example"
if _, err := os.Stat(file); os.IsNotExist(err) {
tt := TextTransformation{"Hello, World!", UpperCaseTransformation{}}
// Note: didn't need to refer to concrete type explicitly
gob.Register(tt.Transformation)
f, err := os.Create(file)
panicOnError(err)
defer f.Close()
enc := gob.NewEncoder(f)
err = enc.Encode(tt)
panicOnError(err)
fmt.Println("Run complete, run again for error.")
} else {
f, err := os.Open(file)
panicOnError(err)
defer os.Remove(f.Name())
defer f.Close()
var newTT TextTransformation
dec := gob.NewDecoder(f)
// Errors with: `gob: name not registered for interface: "main.UpperCaseTransformation"'
err = dec.Decode(&newTT)
panicOnError(err)
}
}
我的解决方法是要求接口的实现者向gob注册其类型。但是我不喜欢这样向调用者显示我的序列化选择。
有没有避免这种情况的前进路线?
该encoding/gob
程序包不能(或者应该不应该)自己做出决定。由于该gob
包创建了独立于应用程序或与应用程序分离的序列化形式,因此无法保证解码器中将存在接口类型的值;即使它们确实做到了(与具体类型名称匹配),也无法保证它们代表相同的类型(或给定类型的相同实现)。
通过调用gob.Register()
(或gob.RegisterName()
)您可以清楚地表明
意图 ,您可以使gob
包装使用绿灯。这还可以确保该类型 确实 存在,否则在注册时您将无法传递其值。
还有一种技术观点规定了此要求(必须事先注册):您无法获得reflect.Type
由其string
名称给出的类型的类型描述符。不仅您自己,encoding/gob
包装也不能做到。
因此,通过要求您gob.Register()
事先调用,gob
程序包将接收到相关类型的值,因此它可以(并且将)在reflect.Type
内部访问和存储其描述符,因此,当检测到该类型的值时,它就可以创建这种类型的新值(例如使用reflect.New()
)的过程,以便将要解码的值存储到其中。
您不能按名称“查找”类型的原因是,除非您明确引用它们,否则它们可能不会出现在二进制文件中(它们可能会被“优化”)。注册自定义类型时(通过传递它们的值),您将对它们进行显式引用,从而确保它们不会从二进制文件中排除。
我想将带入原型。事先不知道它是什么类型的消息。 为了添加更多细节,我知道编码类型/消息可以是的类型集。(它们都是在我自己的proto文件中声明并内置到Go二进制文件中的类型。) 我想看看是否有可能获取一个字节数组并从中重建原始消息。 我写了这个演示:https://play.golang.org/p/WF9KpTlZnp7如果我传递描述符,我可以将其解码为Dynamicpb,并从任何返回消息。
本文向大家介绍MySQL在不知道列名情况下的注入详解,包括了MySQL在不知道列名情况下的注入详解的使用技巧和注意事项,需要的朋友参考一下 前言 最近感觉脑子空空,全在为了刷洞去挖洞,还是回归技术的本身让自己舒服些。好了,下面话不多说了,来一起看看详细的介绍吧 前提 以下情况适用于 MySQL < 5版本,或者在 MySQL >= 5 的版本[存在information_schema库],且已获取
我使用键值存储作为我的Go语言应用程序的后端,日期作为键(保持条目排序),json文档作为值。json的顶级命名空间()以及和存在于我存储的每个json文档中,但在其他方面存在一些差异(尤其是关于一些嵌套的json数据),所以当keyI从数据库中提取时,我真的不知道我在循环浏览的任何时间提取了什么。这是json数据的示例 当我从数据库中提取数据时,我要做的第一件事是将每个条目解组到<code>ma
如果我不知道一个物体的深度,我如何移除另一个物体内部的一个物体? json对象 假设我想删除“4”,但是“4”可能是第一级孩子或者在另一个孩子里面?
问题内容: 我试图解析Java中的JSON字符串并找到键值对,以便我可以确定JSON对象的近似结构,因为JSON字符串的对象结构是未知的。 例如,一个执行可能具有这样的JSON字符串: 另一个像这样: 如何遍历各种JSON元素并确定键及其值?我看着的。我知道如何获取下一个“令牌”并确定令牌的类型(即字段名称,值,数组开头等),但是,我不知道如何获取实际令牌的值。 例如: 或其他库(或)中是否有一个
我知道协议缓冲区是一种序列化格式,需要中的消息格式。proto,以便正确读回。但我有一个文件,我不知道正确的消息格式,因为它没有发布。我想做的是自己对数据进行反向工程,这样我就可以重建消息。为此,我需要读取原始文件,从中可以提取字段编号、类型和值。 有没有一个程序可以做到这一点(最好是在python中,但C/C也很酷)?