2017-03-08 99 views
1

我試圖使用go的net/rpc包來發送數據結構。數據結構包含一個指向uint64的指針。指針永遠不會爲零,但值可能爲0.我發現當值爲0時,接收器會看到一個零指針。當該值爲非0時,接收者看到一個非零指針指向一個適當的值。這是有問題的,因爲這意味着RPC打破了我的數據結構的一個不變性:指針永遠不會爲零。golang gob將指針轉換爲0爲零指針

我有一個去遊樂場,這裏演示了此行爲:https://play.golang.org/p/Un3bTe5F-P

package main 

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

type P struct { 
    Zero, One int 
    Ptr *int 
} 

func main() { 
    // Initialize the encoder and decoder. Normally enc and dec would be 
    // bound to network connections and the encoder and decoder would 
    // run in different processes. 
    var network bytes.Buffer  // Stand-in for a network connection 
    enc := gob.NewEncoder(&network) // Will write to network. 
    dec := gob.NewDecoder(&network) // Will read from network. 
    // Encode (send) the value. 
    var p P 
    p.Zero = 0 
    p.One = 1 
    p.Ptr = &p.Zero 
    fmt.Printf("p0: %s\n", p) 
    err := enc.Encode(p) 
    if err != nil { 
     log.Fatal("encode error:", err) 
    } 
    // Decode (receive) the value. 
    var q P 
    err = dec.Decode(&q) 
    if err != nil { 
     log.Fatal("decode error:", err) 
    } 
    fmt.Printf("q0: %s\n", q) 

    p.Ptr = &p.One 
    fmt.Printf("p1: %s\n", p) 
    err = enc.Encode(p) 
    if err != nil { 
     log.Fatal("encode error:", err) 
    } 

    err = dec.Decode(&q) 
    if err != nil { 
     log.Fatal("decode error:", err) 
    } 
    fmt.Printf("q1: %s\n", q) 
} 

從這段代碼的輸出是:

p0: {%!s(int=0) %!s(int=1) %!s(*int=0x1050a780)} 
q0: {%!s(int=0) %!s(int=1) %!s(*int=<nil>)} 
p1: {%!s(int=0) %!s(int=1) %!s(*int=0x1050a784)} 
q1: {%!s(int=0) %!s(int=1) %!s(*int=0x1050aba8)} 

所以當ptr指向一個0,就變成在零接收端。當Ptr指向1時,它正常通過。

這是一個錯誤?有沒有解決這個問題的方法?我想避免解組在接收端我detastructure解決所有意想不到的零指針...

+0

這看起來像一個錯誤,但它可能是gob格式的限制。如果你有一個不變的指向整數的指針永遠不會是零,那爲什麼它是一個指針? – JimB

+0

@JimB該結構是解析JSON的結果,我需要知道字段是否存在。 Go的JSON解析庫爲此使用指針。 – user7678959

回答

1

此行爲是根據在2013年提出回缺陷的採空區協議的限制 - 見https://github.com/golang/go/issues/4609

請記住,gob不發送指針,指針被解除引用並且值被傳遞。因此,當p.Ptr設置爲& p.One時,您會發現q.Ptr!= & q.One