猿问

使用指针序列化结构

具有如下结构层次结构:


type DomainStore struct {

    Domains []*Domain

    Users []*User

}


type Domain struct {

    Name    string

    Records []*Record

    Owner   *User

}


type User struct {

    Name      string

    Email     string

    Domains []*Domain

}


type Record struct {

    Name      string

    Host      string

}

使用具有域和用户列表的单个 DomainStore,以及域和用户之间的指针。


我正在寻找一种对文件进行序列化/反序列化的方法。我一直在尝试使用 gob,但指针没有(按设计)序列化正确(扁平化)。


考虑给每个对象一个唯一的 id 并制作一个函数来序列化/反序列化每种类型,但这似乎需要很多工作/样板。对策略有什么建议吗?


我想将整个 DomainStore 保存在内存中,并根据用户请求序列化为文件。


主要问题:如何序列化/反序列化并保持指针指向同一个对象而不是同一个对象的不同副本


gob 和 json 似乎都“只是”复制对象的值并进行反序列化,我最终得到了多个独立的对象副本。


使用 gob ang json 会发生以下情况:


之前,A & C 都指向 B:


A -> B <- C

使用 json/gob 反序列化后:


A -> B1 , C -> B2

A & C 指向不同的对象,具有相同的值。但是,如果我更改 B1,它不会在 B2 中更改。


- - 更新 - -


编组时我可以获得对象的内存位置并将其用作 ID:


func (u *User) MarshalJSON() ([]byte, error) {

    return json.Marshal(&JsonUser{

        ID:       fmt.Sprintf("%p", u),

        Name:     u.Name,

        Email:    u.Email,

    })

}

在编组域时,我可以替换


func (d *Domain) MarshalJSON() ([]byte, error) {

    return json.Marshal(&struct {

        ID       string `json:"id"`

        Name     string `json:"name"`

        User     string `json:"user"`

    }{

        ID:       fmt.Sprintf("%p", d),

        Name:     d.Name,

        User:     fmt.Sprintf("%p", d.User),

    })

}

现在我只需要能够解组这个,这给我带来了一个问题,UnmarshalJSON 需要访问 id 及其各自对象的映射。


func (u *User) UnmarshalJSON(data []byte) error {

  // need acces to a map shared by all UnmarshalJSON functions

}


天涯尽头无女友
浏览 109回答 2
2回答

慕森卡

可以使用以下方法完成:所有对象都放置在地图中的状态对象中。当 State 对象中的对象被编组时,所有使用指针引用的对象都将替换为该对象的内存位置。当使用先前读取的对象的全局列表恢复未编组的指针时。代码将运行,只是为了说明方法,我是 Go 的新手,所以请耐心等待。package mainimport (&nbsp; &nbsp; "encoding/json"&nbsp; &nbsp; "errors"&nbsp; &nbsp; "fmt"&nbsp; &nbsp; "log"&nbsp; &nbsp; "strings")type User struct {&nbsp; &nbsp; Name&nbsp; string&nbsp; &nbsp; Email string}type JsonUser struct {&nbsp; &nbsp; ID&nbsp; &nbsp; string `json:"id"`&nbsp; &nbsp; Name&nbsp; string `json:"name"`&nbsp; &nbsp; Email string `json:"email"`}func (u *User) Print(level int) {&nbsp; &nbsp; ident := strings.Repeat("-", level)&nbsp; &nbsp; log.Println(ident, "Username:", u.Name, u.Email)}func (u *User) Id() string {&nbsp; &nbsp; return fmt.Sprintf("%p", u)}func (u *User) MarshalJSON() ([]byte, error) {&nbsp; &nbsp; return json.Marshal(&JsonUser{&nbsp; &nbsp; &nbsp; &nbsp; ID:&nbsp; &nbsp; u.Id(),&nbsp; &nbsp; &nbsp; &nbsp; Name:&nbsp; u.Name,&nbsp; &nbsp; &nbsp; &nbsp; Email: u.Email,&nbsp; &nbsp; })}func (u *User) UnmarshalJSON(data []byte) error {&nbsp; &nbsp; aux := &JsonUser{}&nbsp; &nbsp; if err := json.Unmarshal(data, &aux); err != nil {&nbsp; &nbsp; &nbsp; &nbsp; return err&nbsp; &nbsp; }&nbsp; &nbsp; u.Name = aux.Name&nbsp; &nbsp; u.Email = aux.Email&nbsp; &nbsp; load_helper[aux.ID] = u&nbsp; &nbsp; log.Println("Added user with id ", aux.ID, u.Name)&nbsp; &nbsp; return nil}type Record struct {&nbsp; &nbsp; Type&nbsp; &nbsp; &nbsp;string // MX / A / CNAME / TXT / REDIR / SVR&nbsp; &nbsp; Name&nbsp; &nbsp; &nbsp;string // @ / www&nbsp; &nbsp; Host&nbsp; &nbsp; &nbsp;string // IP / address&nbsp; &nbsp; Priority int&nbsp; &nbsp; // Used for MX&nbsp; &nbsp; Port&nbsp; &nbsp; &nbsp;int&nbsp; &nbsp; // Used for SVR}type JsonRecord struct {&nbsp; &nbsp; ID&nbsp; &nbsp; &nbsp; &nbsp;string&nbsp; &nbsp; Type&nbsp; &nbsp; &nbsp;string&nbsp; &nbsp; Name&nbsp; &nbsp; &nbsp;string&nbsp; &nbsp; Host&nbsp; &nbsp; &nbsp;string&nbsp; &nbsp; Priority int&nbsp; &nbsp; Port&nbsp; &nbsp; &nbsp;int}func (r *Record) Print(level int) {&nbsp; &nbsp; ident := strings.Repeat("-", level)&nbsp; &nbsp; log.Println(ident, "", r.Type, r.Name, r.Host)}func (r *Record) Id() string {&nbsp; &nbsp; return fmt.Sprintf("%p", r)}func (r *Record) MarshalJSON() ([]byte, error) {&nbsp; &nbsp; return json.Marshal(&JsonRecord{&nbsp; &nbsp; &nbsp; &nbsp; ID:&nbsp; &nbsp; &nbsp; &nbsp;r.Id(),&nbsp; &nbsp; &nbsp; &nbsp; Name:&nbsp; &nbsp; &nbsp;r.Name,&nbsp; &nbsp; &nbsp; &nbsp; Type:&nbsp; &nbsp; &nbsp;r.Type,&nbsp; &nbsp; &nbsp; &nbsp; Host:&nbsp; &nbsp; &nbsp;r.Host,&nbsp; &nbsp; &nbsp; &nbsp; Priority: r.Priority,&nbsp; &nbsp; &nbsp; &nbsp; Port:&nbsp; &nbsp; &nbsp;r.Port,&nbsp; &nbsp; })}func (r *Record) UnmarshalJSON(data []byte) error {&nbsp; &nbsp; aux := &JsonRecord{}&nbsp; &nbsp; if err := json.Unmarshal(data, &aux); err != nil {&nbsp; &nbsp; &nbsp; &nbsp; return err&nbsp; &nbsp; }&nbsp; &nbsp; r.Name = aux.Name&nbsp; &nbsp; r.Type = aux.Type&nbsp; &nbsp; r.Host = aux.Host&nbsp; &nbsp; r.Priority = aux.Priority&nbsp; &nbsp; r.Port = aux.Port&nbsp; &nbsp; load_helper[aux.ID] = r&nbsp; &nbsp; log.Println("Added record with id ", aux.ID, r.Name)&nbsp; &nbsp; return nil}type Domain struct {&nbsp; &nbsp; Name&nbsp; &nbsp; string&nbsp; &nbsp; User&nbsp; &nbsp; *User&nbsp; &nbsp; &nbsp;// User ID&nbsp; &nbsp; Records []*Record // Record ID's}type JsonDomain struct {&nbsp; &nbsp; ID&nbsp; &nbsp; &nbsp; string&nbsp; &nbsp;`json:"id"`&nbsp; &nbsp; Name&nbsp; &nbsp; string&nbsp; &nbsp;`json:"name"`&nbsp; &nbsp; User&nbsp; &nbsp; string&nbsp; &nbsp;`json:"user"`&nbsp; &nbsp; Records []string `json:"records"`}func (d *Domain) Print(level int) {&nbsp; &nbsp; ident := strings.Repeat("-", level)&nbsp; &nbsp; log.Println(ident, "Domain:", d.Name)&nbsp; &nbsp; d.User.Print(level + 1)&nbsp; &nbsp; log.Println(ident, " Records:")&nbsp; &nbsp; for _, r := range d.Records {&nbsp; &nbsp; &nbsp; &nbsp; r.Print(level + 2)&nbsp; &nbsp; }}func (d *Domain) Id() string {&nbsp; &nbsp; return fmt.Sprintf("%p", d)}func (d *Domain) MarshalJSON() ([]byte, error) {&nbsp; &nbsp; var record_ids []string&nbsp; &nbsp; for _, r := range d.Records {&nbsp; &nbsp; &nbsp; &nbsp; record_ids = append(record_ids, r.Id())&nbsp; &nbsp; }&nbsp; &nbsp; return json.Marshal(JsonDomain{&nbsp; &nbsp; &nbsp; &nbsp; ID:&nbsp; &nbsp; &nbsp; d.Id(),&nbsp; &nbsp; &nbsp; &nbsp; Name:&nbsp; &nbsp; d.Name,&nbsp; &nbsp; &nbsp; &nbsp; User:&nbsp; &nbsp; d.User.Id(),&nbsp; &nbsp; &nbsp; &nbsp; Records: record_ids,&nbsp; &nbsp; })}func (d *Domain) UnmarshalJSON(data []byte) error {&nbsp; &nbsp; log.Println("UnmarshalJSON domain")&nbsp; &nbsp; aux := &JsonDomain{}&nbsp; &nbsp; if err := json.Unmarshal(data, &aux); err != nil {&nbsp; &nbsp; &nbsp; &nbsp; return err&nbsp; &nbsp; }&nbsp; &nbsp; d.Name = aux.Name&nbsp; &nbsp; d.User = load_helper[aux.User].(*User) // restore pointer to domains user&nbsp; &nbsp; for _, record_id := range aux.Records {&nbsp; &nbsp; &nbsp; &nbsp; d.Records = append(d.Records, load_helper[record_id].(*Record))&nbsp; &nbsp; }&nbsp; &nbsp; return nil}type State struct {&nbsp; &nbsp; Users&nbsp; &nbsp;map[string]*User&nbsp; &nbsp; Records map[string]*Record&nbsp; &nbsp; Domains map[string]*Domain}func NewState() *State {&nbsp; &nbsp; s := &State{}&nbsp; &nbsp; s.Users = make(map[string]*User)&nbsp; &nbsp; s.Domains = make(map[string]*Domain)&nbsp; &nbsp; s.Records = make(map[string]*Record)&nbsp; &nbsp; return s}func (s *State) Print() {&nbsp; &nbsp; log.Println("State:")&nbsp; &nbsp; log.Println("Users:")&nbsp; &nbsp; for _, u := range s.Users {&nbsp; &nbsp; &nbsp; &nbsp; u.Print(1)&nbsp; &nbsp; }&nbsp; &nbsp; log.Println("Domains:")&nbsp; &nbsp; for _, d := range s.Domains {&nbsp; &nbsp; &nbsp; &nbsp; d.Print(1)&nbsp; &nbsp; }}func (s *State) NewUser(name string, email string) *User {&nbsp; &nbsp; u := &User{Name: name, Email: email}&nbsp; &nbsp; id := fmt.Sprintf("%p", u)&nbsp; &nbsp; s.Users[id] = u&nbsp; &nbsp; return u}func (s *State) NewDomain(user *User, name string) *Domain {&nbsp; &nbsp; d := &Domain{Name: name, User: user}&nbsp; &nbsp; s.Domains[d.Id()] = d&nbsp; &nbsp; return d}func (s *State) NewMxRecord(d *Domain, rtype string, name string, host string, priority int) *Record {&nbsp; &nbsp; r := &Record{Type: rtype, Name: name, Host: host, Priority: priority}&nbsp; &nbsp; d.Records = append(d.Records, r)&nbsp; &nbsp; s.Records[r.Id()] = r&nbsp; &nbsp; return r}func (s *State) FindDomain(name string) (*Domain, error) {&nbsp; &nbsp; for _, v := range s.Domains {&nbsp; &nbsp; &nbsp; &nbsp; if v.Name == name {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return v, nil&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; return nil, errors.New("Not found")}func Save(s *State) (string, error) {&nbsp; &nbsp; b, err := json.MarshalIndent(s, "", "&nbsp; &nbsp; ")&nbsp; &nbsp; if err == nil {&nbsp; &nbsp; &nbsp; &nbsp; return string(b), nil&nbsp; &nbsp; } else {&nbsp; &nbsp; &nbsp; &nbsp; log.Println(err)&nbsp; &nbsp; &nbsp; &nbsp; return "", err&nbsp; &nbsp; }}var load_helper map[string]interface{}func Load(s *State, blob string) {&nbsp; &nbsp; load_helper = make(map[string]interface{})&nbsp; &nbsp; if err := json.Unmarshal([]byte(blob), s); err != nil {&nbsp; &nbsp; &nbsp; &nbsp; log.Println(err)&nbsp; &nbsp; } else {&nbsp; &nbsp; &nbsp; &nbsp; log.Println("OK")&nbsp; &nbsp; }}func test_state() {&nbsp; &nbsp; s := NewState()&nbsp; &nbsp; u := s.NewUser("Ownername", "some@email.com")&nbsp; &nbsp; d := s.NewDomain(u, "somedomain.com")&nbsp; &nbsp; s.NewMxRecord(d, "MX", "@", "192.168.1.1", 10)&nbsp; &nbsp; s.NewMxRecord(d, "A", "www", "192.168.1.1", 0)&nbsp; &nbsp; s.Print()&nbsp; &nbsp; x, _ := Save(s) // Saved to json string&nbsp; &nbsp; log.Println("State saved, the json string is:")&nbsp; &nbsp; log.Println(x)&nbsp; &nbsp; s2 := NewState() // Create a new empty State&nbsp; &nbsp; Load(s2, x)&nbsp; &nbsp; s2.Print()&nbsp; &nbsp; d, err := s2.FindDomain("somedomain.com")&nbsp; &nbsp; if err == nil {&nbsp; &nbsp; &nbsp; &nbsp; d.User.Name = "Changed"&nbsp; &nbsp; } else {&nbsp; &nbsp; &nbsp; &nbsp; log.Println("Error:", err)&nbsp; &nbsp; }&nbsp; &nbsp; s2.Print()}func main() {&nbsp; &nbsp; test_state()}这是相当多的代码,对象和序列化之间有很多耦合。全局变量 load_helper 也不好。改进的想法将不胜感激。另一种方法是使用反射来制作更通用的解决方案。以下是使用此方法的示例:package mainimport (&nbsp; &nbsp; "encoding/json"&nbsp; &nbsp; "fmt"&nbsp; &nbsp; "log"&nbsp; &nbsp; "strings"&nbsp; &nbsp; "reflect")func pprint(x interface{}) {&nbsp; &nbsp; b, err := json.MarshalIndent(x, "", "&nbsp; ")&nbsp; &nbsp; if err != nil {&nbsp; &nbsp; &nbsp; &nbsp; fmt.Println("error:", err)&nbsp; &nbsp; }&nbsp; &nbsp; fmt.Println(string(b))&nbsp;&nbsp;}var typeRegistry = make(map[string]reflect.Type)// Register a type to make it possible for the Save/Load functions// to serialize it.func Register(v interface{}) {&nbsp; &nbsp; t := reflect.TypeOf(v)&nbsp; &nbsp; n := t.Name()&nbsp; &nbsp; fmt.Println("Register type",n)&nbsp; &nbsp; typeRegistry[n] = reflect.TypeOf(v)}// Make an instance of a type from the string name of the type.func makeInstance(name string) reflect.Value {&nbsp; &nbsp; v := reflect.New(typeRegistry[name]).Elem()&nbsp; &nbsp; return v}// Translate a string type name tpo a real type.func getTypeFromString(name string) reflect.Type {&nbsp; &nbsp; return typeRegistry[name]}// Serializeable interface must be supported by all objects passed to the Load / Save functions.type Serializeable interface {&nbsp; &nbsp; Id() string}// GenericSave saves the object dfunc GenericSave(d interface{}) (string, error) {&nbsp; &nbsp; r := make(map[string]interface{})&nbsp; &nbsp; v := reflect.ValueOf(d)&nbsp; &nbsp; t := reflect.TypeOf(d)&nbsp; &nbsp; if t.Kind()==reflect.Ptr {&nbsp; &nbsp; &nbsp; &nbsp; t=t.Elem()&nbsp; &nbsp; &nbsp; &nbsp; v=v.Elem()&nbsp; &nbsp; }&nbsp; &nbsp; r["_TYPE"]=t.Name()&nbsp; &nbsp; r["_ID"]=fmt.Sprintf("%p", d)&nbsp; &nbsp; for i := 0; i < t.NumField(); i++ {&nbsp; &nbsp; &nbsp; &nbsp; f := t.Field(i)&nbsp; &nbsp; &nbsp; &nbsp; name := f.Name&nbsp; &nbsp; &nbsp; &nbsp; vf := v.FieldByName(name)//&nbsp; &nbsp; &nbsp; fmt.Println("Field", i+1, "name is", name, "type is", f.Type.Name(), "and kind is", f.Type.Kind())&nbsp; &nbsp; &nbsp;&nbsp;//&nbsp; &nbsp; &nbsp; fmt.Println("V:", vf)&nbsp; &nbsp; &nbsp; &nbsp; if f.Tag != "" {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; store:=strings.Split(f.Tag.Get("store"),",")&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; switch store[1] {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case "v":&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; switch t.Field(i).Type.Name() {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case "string":&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; r[store[0]]=vf.String()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case "int":&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; r[store[0]]=vf.Int()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case "p":&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; vals:=vf.MethodByName("Id").Call([]reflect.Value{})&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; r[store[0]]=vals[0].String()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case "lp":&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; tr:=[]string{}&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for j := 0; j < vf.Len(); j++ {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; vals:=vf.Index(j).MethodByName("Id").Call([]reflect.Value{})&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; tr=append(tr,vals[0].String())&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; r[store[0]]=tr&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp;&nbsp; &nbsp; m,_:=json.Marshal(r)&nbsp; &nbsp; return string(m),nil}// Save saves the list of objects.func Save(objects []Serializeable) []byte {&nbsp; &nbsp; lst:=[]string{}&nbsp; &nbsp; for _,o := range(objects) {&nbsp; &nbsp; &nbsp; &nbsp; os,_:= GenericSave(o) // o.Save()&nbsp; &nbsp; &nbsp; &nbsp; lst=append(lst,os)&nbsp; &nbsp; }&nbsp; &nbsp; m,_:=json.Marshal(lst)&nbsp; &nbsp; return m}func toStructPtr(obj interface{}) interface{} {&nbsp; &nbsp; vp := reflect.New(reflect.TypeOf(obj))&nbsp; &nbsp; vp.Elem().Set(reflect.ValueOf(obj))&nbsp; &nbsp; return vp.Interface()}// Load creates a list of serializeable objects from json blobfunc Load(blob []byte) []Serializeable {&nbsp; &nbsp; objects := []Serializeable{}&nbsp; &nbsp; loadHelper := make(map[string]interface{})&nbsp; &nbsp; var olist []interface{}&nbsp; &nbsp; if err := json.Unmarshal(blob, &olist); err != nil {&nbsp; &nbsp; &nbsp; &nbsp; log.Println(err)&nbsp; &nbsp; } else {&nbsp; &nbsp; &nbsp; &nbsp; for _,o := range(olist) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var omap map[string]interface{}&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; json.Unmarshal([]byte(o.(string)), &omap)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; t:= getTypeFromString(omap["_TYPE"].(string))&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; obj := reflect.New(t).Elem()&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for i := 0; i < t.NumField(); i++ {//&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; n:=t.Field(i).Name//&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fmt.Println(i,n,t.Field(i).Type.Name())&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if t.Field(i).Tag != "" {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; store:=strings.Split(t.Field(i).Tag.Get("store"),",")//&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fmt.Println(store)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; switch store[1] {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case "v":&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; switch t.Field(i).Type.Name() {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case "string":&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; obj.FieldByIndex([]int{i}).SetString(omap[store[0]].(string))&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case "int":&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; obj.FieldByIndex([]int{i}).SetInt(int64(omap[store[0]].(float64)))&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case "p":&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; nObj:=loadHelper[omap[store[0]].(string)]&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; obj.FieldByIndex([]int{i}).Set(reflect.ValueOf(nObj.(*User)))&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case "lp":&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ptrItemType:=t.Field(i).Type.Elem()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; slice := reflect.Zero(reflect.SliceOf(&nbsp; ptrItemType /* reflect.TypeOf( &Record{} ) */&nbsp; ))//.Interface()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for _, pID := range(omap[store[0]].([]interface{})) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; nObj:=loadHelper[pID.(string)]&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; slice=reflect.Append(slice,&nbsp; reflect.ValueOf(nObj)&nbsp; )&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; obj.FieldByIndex([]int{i}).Set(slice)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; oi:=toStructPtr(obj.Interface())&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; oip:=oi.(Serializeable)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; objects=append(objects,oip)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; loadHelper[omap["_ID"].(string)]=oip&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; return objects}/* Application data structures */type User struct {&nbsp; &nbsp; Name&nbsp; string `store:"name,v"`&nbsp; &nbsp; Email string `store:"email,v"`}func (u *User) Id() string {&nbsp; &nbsp; return fmt.Sprintf("%p", u)}func (u *User) Save() (string, error) {&nbsp; &nbsp; return GenericSave(u)}func (u *User) Print() {&nbsp; &nbsp; fmt.Println("User:",u.Name)}type Record struct {&nbsp; &nbsp; Type&nbsp; &nbsp; &nbsp;string `store:"type,v"`// MX / A / CNAME / TXT / REDIR / SVR&nbsp; &nbsp; Name&nbsp; &nbsp; &nbsp;string `store:"name,v"`// @ / www&nbsp; &nbsp; Host&nbsp; &nbsp; &nbsp;string `store:"host,v"`// IP / address&nbsp; &nbsp; Priority int&nbsp; &nbsp; `store:"priority,v"`// Used for MX&nbsp; &nbsp; Port&nbsp; &nbsp; &nbsp;int&nbsp; &nbsp; `store:"port,v"`// Used for SVR}func (r *Record) Id() string {&nbsp; &nbsp; return fmt.Sprintf("%p", r)}func (r *Record) Save() (string, error) {&nbsp; &nbsp; return GenericSave(r)}func (r *Record) Print() {&nbsp; &nbsp; fmt.Println("Record:",r.Type,r.Name,r.Host)}type Domain struct {&nbsp; &nbsp; Name&nbsp; &nbsp; string&nbsp; &nbsp; `store:"name,v"`&nbsp; &nbsp; User&nbsp; &nbsp; *User&nbsp; &nbsp; &nbsp;`store:"user,p"`&nbsp; &nbsp; // User ID&nbsp; &nbsp; Records []*Record `store:"record,lp"` // Record ID's}func (d *Domain) Id() string {&nbsp; &nbsp; return fmt.Sprintf("%p", d)}func (d *Domain) Save() (string, error) {&nbsp; &nbsp; return GenericSave(d)}func (d *Domain) Print() {&nbsp; &nbsp; fmt.Println("Domain:",d.Name)&nbsp; &nbsp; d.User.Print()&nbsp; &nbsp; fmt.Println("Records:")&nbsp; &nbsp; for _, r := range d.Records {&nbsp; &nbsp; &nbsp; &nbsp; r.Print()&nbsp; &nbsp; }}type DBM struct {&nbsp; &nbsp; Domains []*Domain&nbsp; &nbsp; Users []*User&nbsp; &nbsp; Records []*Record}func (dbm *DBM) AddDomain(d *Domain) {&nbsp; &nbsp; dbm.Domains=append(dbm.Domains,d)}func (dbm *DBM) AddUser(u *User) {&nbsp; &nbsp; dbm.Users=append(dbm.Users,u)}func (dbm *DBM) AddRecord(r *Record) {&nbsp; &nbsp; dbm.Records=append(dbm.Records,r)}func (dbm *DBM) GetObjects() []Serializeable {&nbsp; &nbsp; objects:=[]Serializeable{}&nbsp; &nbsp; for _,r := range(dbm.Records) {&nbsp; &nbsp; &nbsp; &nbsp; objects=append(objects, r)&nbsp; &nbsp; }&nbsp; &nbsp; for _,u := range(dbm.Users) {&nbsp; &nbsp; &nbsp; &nbsp; objects=append(objects, u)&nbsp; &nbsp; }&nbsp; &nbsp; for _,d := range(dbm.Domains) {&nbsp; &nbsp; &nbsp; &nbsp; objects=append(objects, d)&nbsp; &nbsp; }&nbsp; &nbsp; return objects}func (dbm *DBM) SetObjects(objects []Serializeable) {&nbsp; &nbsp; for _,o := range(objects) {&nbsp; &nbsp; &nbsp; &nbsp; switch o.(type) {&nbsp; &nbsp; &nbsp; &nbsp; case *Record:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fmt.Println("record")&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; dbm.AddRecord(o.(*Record))&nbsp; &nbsp; &nbsp; &nbsp; case *User:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fmt.Println("record")&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; dbm.AddUser(o.(*User))&nbsp; &nbsp; &nbsp; &nbsp; case *Domain:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fmt.Println("record")&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; dbm.AddDomain(o.(*Domain))&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }}func testState() {&nbsp; &nbsp; Register(User{})&nbsp; &nbsp; Register(Domain{})&nbsp; &nbsp; Register(Record{})&nbsp; &nbsp; dbm:=DBM{}&nbsp; &nbsp; u := &User{Name: "Martin", Email: "some@email.com"}&nbsp; &nbsp; dbm.AddUser(u)&nbsp; &nbsp; r1 := &Record{Name: "@", Type: "MX", Host: "mail.ishost.dk"}&nbsp; &nbsp; r2 := &Record{Name: "@", Type: "MX", Host: "mail.infoserv.dk"}&nbsp; &nbsp; dbm.AddRecord(r1)&nbsp; &nbsp; dbm.AddRecord(r2)&nbsp; &nbsp; d := &Domain{User:u, Name: "Martin", Records: []*Record{r1, r2}}&nbsp; &nbsp; dbm.AddDomain(d)&nbsp; &nbsp; x:=Save(dbm.GetObjects())&nbsp; &nbsp; fmt.Println("== Saved objects")//&nbsp; fmt.Println(string(x))&nbsp; &nbsp; fmt.Println("== Loading")&nbsp; &nbsp; dbm2:=DBM{}&nbsp; &nbsp; dbm2.SetObjects(Load(x))&nbsp; &nbsp; u2:=dbm2.Users[0]&nbsp; &nbsp; u2.Print()&nbsp; &nbsp; u2.Name="KURT"&nbsp; &nbsp; u2.Print()&nbsp; &nbsp; d2:=dbm2.Domains[0]&nbsp; &nbsp; d2.Print()&nbsp; &nbsp; d2.User.Name="ZIG"&nbsp; &nbsp; u2.Print()}func main() {&nbsp; &nbsp; testState()}

开心每一天1111

使用encoding/json包元帅:// Marshal is a function that marshals the object into an// io.Reader.// By default, it uses the JSON marshaller.var Marshal = func(v interface{}) (io.Reader, error) {&nbsp; b, err := json.MarshalIndent(v, "", "\t")&nbsp; if err != nil {&nbsp; &nbsp; return nil, err&nbsp; }&nbsp; return bytes.NewReader(b), nil}解组:// Unmarshal is a function that unmarshals the data from the// reader into the specified value.// By default, it uses the JSON unmarshaller.var Unmarshal = func(r io.Reader, v interface{}) error {&nbsp; return json.NewDecoder(r).Decode(v)}不确定还有更多,您可以做的另一件事是,将所有这些存储为 json 格式的字符串。
随时随地看视频慕课网APP

相关分类

Go
我要回答