2017-03-08 2 views
1

J'essaye d'utiliser le paquet net/rpc de go pour envoyer des structures de données. La structure de données inclut un pointeur sur uint64. Le pointeur n'est jamais nul, mais la valeur peut être 0. Je constate que lorsque la valeur est 0, le récepteur voit un pointeur nul. Lorsque la valeur est non-0, la réception voit un pointeur non-nul qui pointe vers une valeur correcte. Ceci est problématique, car cela signifie que le RPC brise un invariant de ma structure de données: le pointeur ne sera jamais nul.golang gob convertit le pointeur en 0 en pointeur nul

J'ai un terrain de jeu de go qui illustre ce comportement ici: 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) 
} 

La sortie de ce code est:

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)} 

Ainsi, lorsque Ptr pointe vers 0, il devient nul sur la côté récepteur. Lorsque Ptr pointe à 1, il passe normalement.

Est-ce un bug? Y a-t-il un moyen de contourner ce problème? Je veux éviter d'avoir à unmarshall mon detastructure sur le côté récepteur pour fixer tous les pointeurs nil inattendus ...

+0

qui ressemble à un bug, mais il pourrait être une limitation du format de paraison. Si vous avez un invariant, les pointeurs sur les entiers ne seront jamais nuls, alors pourquoi est-ce un pointeur? – JimB

+0

@JimB La structure est le résultat de l'analyse JSON et j'ai besoin de savoir si un champ est présent ou non. La bibliothèque d'analyse JSON de Go utilise des pointeurs à cet effet. – user7678959

Répondre

1

Ce comportement est une limitation du protocole de paraison selon le défaut soulevé retour en 2013 - voir https://github.com/golang/go/issues/4609

Gardez à l'esprit que gob n'envoie pas de pointeurs, le pointeur est déréférencé et la valeur est passée. En tant que tel lorsque le p.Ptr est réglé sur & p.One, vous constaterez que q.Ptr! = & q.One