2017-05-31 7 views
0

Je veux utiliser gob à encode et decode objet, je le fais comme ceci:Comment marshaler un tableau en binaire et unmarshal binaire en tableau dans golang?

type transProp struct { 
    a []int 
    b []float64 
} 

func (p transProp) MarshalBinary() ([]byte, error) { 
    // A simple encoding: plain text. 
    var b bytes.Buffer 
    fmt.Fprintln(&b, p.a, p.b) 
    return b.Bytes(), nil 
} 

// UnmarshalBinary modifies the receiver so it must take a pointer receiver. 
func (p *transProp) UnmarshalBinary(data []byte) error { 
    // A simple encoding: plain text. 
    b := bytes.NewBuffer(data) 
    _, err := fmt.Fscanln(b, &p.a, &p.b) 
    return err 
} 

func TestGobEncode(t *testing.T) { 
    p := transProp{ 
     a: []int{3, 4, 5}, 
     b: []float64{1.0, 2.0}, 
    } 

    var network bytes.Buffer 
    enc := gob.NewEncoder(&network) 
    err := enc.Encode(p) 
    if err != nil { 
     log.Fatal("encode:", err) 
    } 
    dec := gob.NewDecoder(&network) 
    var p1 transProp 
    err = dec.Decode(&p1) 
    if err != nil { 
     log.Fatal("decode:", err) 
    } 
    fmt.Println(p1) 
} 

Mais, cette erreur de rapport comme celui-ci:

decode:can't scan type: *[]int 
+1

println/Scanln ne sont pas destinés à être utilisés pour la sérialisation. Vous pourriez probablement implémenter 'fmt.Scanner', mais vous pourriez aussi bien le faire directement dans les méthodes du Maréchal que vous avez. – JimB

Répondre

0

Si vous pouvez changer la visibilité des transProp champs au public, par exemple Ensuite, vous n'avez pas besoin d'implémenter un binary marshaller personnalisé/unmarshaller. Vous pouvez utiliser le décodeur/encodeur gob par défaut.

Cependant, si vous ne le pouvez pas, il existe plusieurs options.

  1. Le plus simple, définir une autre wrapper struct qui exportent des domaines connexes, enveloppez transProp, puis utilisez l'encodeur/décodeur par défaut gob, par exemple

    type wrapTransProp struct { 
        A []int 
        B []float64 
    } 
    
    func (p transProp) MarshalBinary() ([]byte, error) { 
        //Wrap struct 
        w := wrapTransProp{p.a, p.b} 
    
        //use default gob encoder 
        var buf bytes.Buffer 
        enc := gob.NewEncoder(&buf) 
        if err := enc.Encode(w); err != nil { 
         return nil, err 
        } 
        return buf.Bytes(), nil 
    } 
    func (p *transProp) UnmarshalBinary(data []byte) error { 
        w := wrapTransProp{} 
    
        //Use default gob decoder 
        reader := bytes.NewReader(data) 
        dec := gob.NewDecoder(reader) 
        if err := dec.Decode(&w); err != nil { 
         return err 
        } 
    
        p.a = w.A 
        p.b = w.B 
        return nil 
    } 
    
  2. sur mesure placier/unmarshaller avec la mise en page de données personnalisées. Il existe de nombreuses possibilités de mise en œuvre. Plusieurs considérations:

    • Ordre des octets, petit/grand endian?
    • Disposition des paquets/flux?

    Un exemple de mise en œuvre big-endian avec le format de flux:

    // Big-Endian 
    // Size : 4,   4,  1,  n,  4,  n 
    // Types : uint32, uint32, uint8, []int, uint32, []float64 
    // Data : #numbytes, #nInt, #intSize, p.a, #nFloat, p.b 
    

    Le défi réside dans la façon de représenter int puisqu'elle est dépendante de l'architecture. la mise en œuvre de l'échantillon sera:

    func (p transProp) MarshalBinary() ([]byte, error) { 
        //Get sizeof int (in bits) from strconv package 
        szInt := strconv.IntSize/8 
        nInt := len(p.a) 
        nFloat := len(p.b) 
    
        nStream := 4 + 4 + 1 + nInt*szInt + 4 + nFloat*8 
        stream := make([]byte, nStream) 
        pos := 0 
    
        //total number of bytes 
        binary.BigEndian.PutUint32(stream, uint32(nStream)) 
        pos += 4 
    
        //num of items in p.a 
        binary.BigEndian.PutUint32(stream[pos:], uint32(nInt)) 
        pos += 4 
    
        //int size 
        stream[pos] = uint8(szInt) 
        pos++ 
    
        //items in a 
        switch szInt { 
        case 1: 
         for _, v := range p.a { 
          stream[pos] = uint8(v) 
          pos++ 
         } 
        case 2: //16-bit 
         for _, v := range p.a { 
          binary.BigEndian.PutUint16(stream[pos:], uint16(v)) 
          pos += 2 
         } 
        case 4: //32-bit 
         for _, v := range p.a { 
          binary.BigEndian.PutUint32(stream[pos:], uint32(v)) 
          pos += 4 
         } 
        case 8: //64-bit 
         for _, v := range p.a { 
          binary.BigEndian.PutUint64(stream[pos:], uint64(v)) 
          pos += 8 
         } 
        } 
    
        //number of items in p.b 
        binary.BigEndian.PutUint32(stream[pos:], uint32(nFloat)) 
        pos += 4 
    
        //items in b 
        s := stream[pos:pos] //slice len=0, capacity=nFloat 
        buf := bytes.NewBuffer(s) 
        if err := binary.Write(buf, binary.BigEndian, p.b); err != nil { 
         return nil, err 
        } 
    
        return stream, nil 
    } 
    
    func (p *transProp) UnmarshalBinary(data []byte) error { 
        buf := bytes.NewBuffer(data) 
    
        var intSize uint8 
        var k, nBytes, nInt, nFloat uint32 
    
        //num bytes 
        if err := binary.Read(buf, binary.BigEndian, &nBytes); err != nil { 
         return err 
        } 
        if len(data) < int(nBytes) { 
         return errors.New("len(data) < #Bytes") 
        } 
    
        //num of int items 
        if err := binary.Read(buf, binary.BigEndian, &nInt); err != nil { 
         return err 
        } 
    
        //int size 
        if err := binary.Read(buf, binary.BigEndian, &intSize); err != nil { 
         return err 
        } 
    
        //read int into p.a 
        pos := 0 
        stream := buf.Bytes() 
        p.a = make([]int, nInt) 
        switch intSize { 
        case 1: 
         for pos = 0; pos < int(nInt); pos++ { 
          p.a[pos] = int(stream[pos]) 
         } 
        case 2: 
         for k = 0; k < nInt; k++ { 
          p.a[k] = int(binary.BigEndian.Uint16(stream[pos:])) 
          pos += 2 
         } 
        case 4: 
         for k = 0; k < nInt; k++ { 
          p.a[k] = int(binary.BigEndian.Uint32(stream[pos:])) 
          pos += 4 
         } 
        case 8: 
         for k = 0; k < nInt; k++ { 
          p.a[k] = int(binary.BigEndian.Uint64(stream[pos:])) 
          pos += 8 
         } 
        } 
    
        //advance buffer 
        buf.Next(pos) 
    
        //num of float64 items 
        if err := binary.Read(buf, binary.BigEndian, &nFloat); err != nil { 
         return err 
        } 
    
        //items in b 
        p.b = make([]float64, nFloat) 
        if err := binary.Read(buf, binary.BigEndian, p.b); err != nil { 
         return err 
        } 
    
        return nil 
    }