2015-09-05 73 views
0

我正在使用數據存儲的appengine應用程序。我正試圖編碼一個接口並將其存儲到數據存儲區 。但是,當我嘗試從 數據存儲負載,我得到的錯誤:gob:接口僅在編碼上註冊,但不在解碼

gob: name not registered for interface: "main27155.strand" 

奇特的事情是load()方法開始有 稱爲save()方法後工作。它不再返回錯誤,並且按預期加載數據存儲中保存的所有內容 。但是當我重新啓動實例時, load()方法再次停止工作。

的加載和保存我提到是指由 datastore.PropertyLoadSaver接口

定義從它的外觀的方法方法,好像與註冊與採空區 類型/接口問題,但我有完全相同同樣的gob.Register()調用 的方法都是load()save()方法。

我甚至嘗試從加載和保存方法 中刪除gob.Register()調用並將其添加到init()。觀察到完全相同的行爲。

如何在冷啓動時加載我的數據存儲?

type bio struct {¬       
    Id  string¬       
    Hp  int¬       
    godie chan bool //should be buffered¬ 
    dam  chan int¬      
    Genetics dna¬       
}¬           

type dna interface { 
    decode() mRNA 
    Get(int) trait 
    Set(int, trait) 
    Duplicate() dna 
    Len() int 
} 
type trait interface { 
    mutate() trait 
} 

// implements dna{} 
type strand []trait 

// implements trait{} 
type tdecoration string 
type color struct { 
    None bool // If true, colors are not shown in theme 
    Bg bool // If true, color is a background color 
    R int // 0-255 
    G int 
    B int 
} 

func start(w http.ResponseWriter, r *http.Request) error { 
    c := appengine.NewContext(r) 

    var bs []bio 
    if _, err := datastore.NewQuery("bio").GetAll(c, &bs); err != nil { 
     log.Println("bs is len: ", len(bs)) 
     return err 
    } 

    ... 
    return nil 
} 

func stop(w http.ResponseWriter, r *http.Request) error { 
    c := appengine.NewContext(r) 
    log.Println("Saving top 20 colors") 
    var k []*datastore.Key 
    var bs []*bio 
    stat := getStats() 
    for i, b := range stat.Leaderboard { 
     k = append(k, datastore.NewKey(c, "bio", b.Id, 0, nil)) 
     bv := b 
     bs = append(bs, &bv) 
     // At most 20 bios survive across reboots 
     if i > 178 { 
      break 
     } 
    } 

    // Assemble slice of keys for deletion 
    dk, err := datastore.NewQuery("bio").KeysOnly().GetAll(c, nil) 
    if err != nil { 
     return errors.New(fmt.Sprintf("Query error: %s", err.Error())) 
    } 

    fn := func(c appengine.Context) error { 
     // Delete all old entries 
     err := datastore.DeleteMulti(c, dk) 
     if err != nil { 
      return errors.New(fmt.Sprintf("Delete error: %s", err.Error())) 
     } 

     // save the elite in the datastore 
     _, err = datastore.PutMulti(c, k, bs) 
     if err != nil { 
      return err 
     } 
     return nil 
    } 

    return datastore.RunInTransaction(c, fn, &datastore.TransactionOptions{XG: true}) 
} 

// satisfy datastore PropertyLoadSaver interface =============================== 

func (b *bio) Load(c <-chan datastore.Property) error { 
    gob.Register(&color{}) 
    gob.Register(new(tdecoration)) 
    var str strand 
    gob.Register(str) 

    tmp := struct { 
     Id  string 
     Hp  int 
     Gengob []byte 
    }{} 
    if err := datastore.LoadStruct(&tmp, c); err != nil { 
     return err 
    } 

    b.Id = tmp.Id 
    b.Hp = tmp.Hp 

    return gob.NewDecoder(strings.NewReader(string(tmp.Gengob))).Decode(&(b.Genetics)) 
} 
func (b *bio) Save(c chan<- datastore.Property) error { 
    defer close(c) 
    gob.Register(&color{}) 
    gob.Register(new(tdecoration)) 
    var str strand 
    gob.Register(str) 

    var buf bytes.Buffer 
    gen := b.Genetics 
    if err := gob.NewEncoder(&buf).Encode(&gen); err != nil { 
     log.Println(err) 
     return err 
    } 
    dp := []datastore.Property{ 
     {Name: "Id", Value: b.Id}, 
     {Name: "Hp", Value: int64(b.Hp)}, 
     {Name: "Gengob", Value: buf.Bytes(), NoIndex: true}, 
    } 
    for _, p := range dp { 
     c <- p 
    } 
    return nil 
} 

附加信息:這種行爲不存在之前,我釀的數據存儲在stop() 調用到datastore.RunInTransaction()

+1

也許這是一個類型不是導出的問題?我很久沒有與gob合作過,所以我對它的工作原理感到生疏。 –

+0

我第二次Not_a_Golfer的懷疑:從編碼/ gib文檔:「Structs編碼和解碼僅導出的領域。」。因爲這可能與appengine,HTTP請求或數據存儲沒有任何關係:您能否在操場上創建可運行的示例? – Volker

+0

gob包編碼未導出的類型就好了。 [實施例](http://play.golang.org/p/-lu435K4Zt)。 OP,請在進行更改後檢查您是否啓動服務器。 –

回答

1

註冊所有類型的中的init()函數中使用RegisterName()。從商店中刪除所有現有數據,你應該很好。

每次構建應用程序時,App Engine都會爲主包生成一個損壞的名稱。由Register()生成的名稱包含此損壞的軟件包名稱。任何使用重名名稱編碼的gobs只能使用應用程序的相同版本進行讀取。如果您通過修改代碼來重建應用程序,那麼應用程序將無法解碼先前存儲的gobs。

+0

你說得對'RegisterName()'我不知道爲什麼它以前沒有工作。謝謝! – borring