【回転】Golang下のencoding関連モジュール使用/go符号化


変換元:https://www.jianshu.com/p/772ca3c6c7ed
encoding/jsonモジュールの使用
パッケージ名:encoding/jsonプログラム開発中に最も一般的なのは、文字列とjson間の変換です.Golangでは、変換媒体としてjson文字列の構造体を定義する必要がある.
marshalとunmarshal
一般的なメソッド関数:
//   v       json   []byte
func Marshal(v interface{}) ([]byte, error)
//              json   
func MarshalIndent(v interface{}, prefix, indent string) ([]byte, error)

// json      []byte,       v 
func Unmarshal(data []byte, v interface{}) error

注意すべき点:
/*
  json   ,    struct tag       :
(1)   tag "-",        JSON
(2)tag        ,          json     
(3)tag   "omitempty"  ,      ,     json
(4)       bool,string,int,int64 , tag   ",string"  ,      json               json   

Marshal                  ,              :
(1)JSON     string  key,     map,     map[string]T    
(2)Channel,complex function       JSON 
(3)           ,    json       
(4)                   ,      null
*/

例:
#  golang        json 
$ cat marshal-test.go
package main

import (
    "fmt"
    "encoding/json"
    _ "bytes"
    "os"
)

type Serverslice struct{
    Servers []Server    `json:"servers"`
}

type Server struct{
    ServerName  string `json:"servername"`
    ServerIP    string `json:"serverip,omitempty"`
}


func main() {
    var s Serverslice
    //func append(slice []Type, elems ...Type) []Type
    s.Servers =  append(s.Servers,Server{ServerName:"Beijing",ServerIP:"10.0.0.1"})
    s.Servers =  append(s.Servers,Server{ServerName:"Xi'an",ServerIP:"10.0.0.2"})
  //slice       [{},{}]       slice    json 
  ss := []Server{{"Beijing","172.0.0.1"},{"Shanghai","172.0.0.2"}}
    b,err := json.Marshal(s)
  if err != nil { os.Exit(1) }
    fmt.Println(string(b))

  bb,err := json.MarshalIndent(ss,"","  ")
  if err == nil { fmt.Println(string(bb)) }

}

//           []struct
//    []struct          
$ go run marshal-test.go
{"servers":[{"servername":"Beijing","serverip":"10.0.0.1"},{"servername":"Xi'an","serverip":"10.0.0.2"}]}
[
  {
    "servername": "Beijing",
    "serverip": "172.0.0.1"
  },
  {
    "servername": "Shanghai",
    "serverip": "172.0.0.2"
  }
]


#  json                

$ cat unmarshal.go
package main
import (
    "fmt"
    "encoding/json"
)


type Server struct {
      ServerName  string `json:"servername"`
      ServerIP  string `json:"serverip"`
}

//    slice
type Serverslice struct{
     Servers []Server
}


func main() {
  //     json   
  str := `{"servers":[{"servername":"Beijing","serverip":"10.0.0.1"},{"servername":"Xi'an","serverip":"10.0.0.2"}]}`
  
  //func Unmarshal(data []byte, v interface{}) error
  //         ,    json    
  var s Serverslice
  // json       s  (          ,                 )
  //     json        []byte      (       )
  if err := json.Unmarshal([]byte(str),&s); err == nil {
      fmt.Println(s)
      fmt.Println(s.Servers)
      fmt.Println(s.Servers[0].ServerName,s.Servers[1].ServerName)

      }


}


decodeとencode
関連関数とメソッド:
//              json  
type Decoder struct {
    // contains filtered or unexported fields
}
//     Decoder  
func NewDecoder(r io.Reader) *Decoder
//Decoder       
func (dec *Decoder) Buffered() io.Reader
func (dec *Decoder) Decode(v interface{}) error
func (dec *Decoder) More() bool
func (dec *Decoder) Token() (Token, error)
func (dec *Decoder) UseNumber()
 
// json               
type Encoder struct {
        // contains filtered or unexported fields
}
//     Encoder  
func NewEncoder(w io.Writer) *Encoder

// json            v     ,   Marshal     
func (enc *Encoder) Encode(v interface{}) error
func (enc *Encoder) SetEscapeHTML(on bool)
func (enc *Encoder) SetIndent(prefix, indent string)
    
    

decodeの例:
$ cat decoder.go
package main
import (
    "encoding/json"
    "fmt"
    "io"
    "log"
    "strings"
)

func main() {
    const jsonStream = `
        {"Name": "Ed", "Text": "Knock knock."}
        {"Name": "Sam", "Text": "Who's there?"}
        {"Name": "Ed", "Text": "Go fmt."}
        {"Name": "Sam", "Text": "Go fmt who?"}
        {"Name": "Ed", "Text": "Go fmt yourself!"}
    `
    type Message struct {
        Name, Text string
    }
  //     Decoder  
  //func NewDecoder(r io.Reader) *Decoder
    dec := json.NewDecoder(strings.NewReader(jsonStream))

    for {
        var m Message
    //   decoder   Decide            v 
    //func (dec *Decoder) Decode(v interface{}) error
    //          
        if err := dec.Decode(&m); err == io.EOF {
            break
        } else if err != nil {
            log.Fatal(err)
        }
        fmt.Printf("%s: %s
", m.Name, m.Text) } } $ go run decode.go Ed: Knock knock. Sam: Who's there? Ed: Go fmt. Sam: Go fmt who? Ed: Go fmt yourself!

encoding/hexモジュールの使用
Hexパケットは主に16進数の文字列の主要関数を符号化および復号するために使用される.
// src   []byte   dst(   DecodedLen(len(src))) ,    dst   
func Decode(dst, src []byte) (int, error)
//  16         []byte
func DecodeString(s string) ([]byte, error)
//x byte      ,   x/2
func DecodedLen(x int) int
//  data dump   ,     `hexdump -C`     
func Dump(data []byte) string
func Dumper(w io.Writer) io.WriteCloser

// src   dst (      EncodedLen(len(src)) )
func Encode(dst, src []byte) int
// []byte      16      
func EncodeToString(src []byte) string
//        ,   n 2 
func EncodedLen(n int) int


例:
$ cat hex.go
package main

import (
    "encoding/hex"
    "fmt"
)

func Something() {
    //func EncodeToString(src []byte) string   byte   16     
    src := []byte("hello")
    fmt.Println(src)                     //[104 101 108 108 111]
    encodeStr := hex.EncodeToString(src) //68656c6c6f 16    
    fmt.Println(encodeStr)

    //func Encode(dst, src []byte) int
    //func EncodedLen(n int) int
    Welcome := []byte("Gopher!")
    Wdest := make([]byte, hex.EncodedLen(len(Welcome)))
    num := hex.Encode(Wdest, Welcome)
    fmt.Println(Wdest, num) //num=14

    //func DecodeString(s string) ([]byte, error)    16       byte  
    decodeStr, _ := hex.DecodeString(encodeStr)
    fmt.Println(string(decodeStr))

    //func DecodedLen(x int) int  x byte      ,   x/2
    //func Decode(dst, src []byte) (int, error)  byte   src   byte   dst ,    dst   
    test := []byte("48656c6c6f20476f7068657221")
    dest := make([]byte, hex.DecodedLen(len(test))) //      
    num, err := hex.Decode(dest, test)              //  16      byte[]  ,      
    if err != nil {
        return
    }
    fmt.Println(num, dest[:num], string(dest), len(dest), cap(dest)) // print 13

    //func Dump(data []byte) string         //                hex dump        linux     "hexdump -C filename"
    content := []byte("Go is an open source programming language.")
    fmt.Println(hex.Dump(content))
}

func main() {
    Something()
}

$ go run hex.go

[104 101 108 108 111]
68656c6c6f
[52 55 54 102 55 48 54 56 54 53 55 50 50 49] 14
hello
13 [72 101 108 108 111 32 71 111 112 104 101 114 33] Hello Gopher! 13 13
00000000  47 6f 20 69 73 20 61 6e  20 6f 70 65 6e 20 73 6f  |Go is an open so|
00000010  75 72 63 65 20 70 72 6f  67 72 61 6d 6d 69 6e 67  |urce programming|
00000020  20 6c 61 6e 67 75 61 67  65 2e                    | language.|

encoding/gobパッケージの使用
gobパケットは、主にバイナリのバイトストリーム間で符号化および復号化されるものを管理するために使用される.1つの典型的な使用例は、net/rpcパケットを使用して、リモート・プロシージャ呼び出し(RPC)におけるパラメータおよび結果を送信することである.
import "encoding/gob"

1.アナログネットワークにおけるバイトストリーム変換
例として、2つの構造体P,Qを定義し、前者はgobが1つのネットワークで符号化(encoder)するデータ構造であり、後者は復号(decoder)するデータ構造である.
package main

/*
  `encoding/gob`        ,       (encoder),     ,       (decoder)    
*/

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

type P struct {
  X, Y, Z int
  Name    string
}

type Q struct {
  X, Y *int32
  Name string
}

func main() {
  //      encoder decoder.t  encoder decoder       ,             
  var network bytes.Buffer        //   buffer        (      )
  enc := gob.NewEncoder(&network) //           
  dec := gob.NewDecoder(&network) //            


  /*
    //NewDecoder     decoder  ,    Decoder   
    func NewDecoder(r io.Reader) *Decoder
    // Decoder     
    func (dec *Decoder) Decode(e interface{}) error
    func (*Decoder) DecodeValue

    //NewEncoder     encoder  ,   Encoder   
    func NewEncoder(w io.Writer) *Encoder
    // Encoder     
    func (enc *Encoder) Encode(e interface{}) error
    func (enc *Encoder) EncodeValue(value reflect.Value) error

  */
  //   enc           
  //   enc.Encode          
  err := enc.Encode(P{6, 6, 8, "xxbandy.github.io"})
  if err != nil {
    log.Fatal("encode error:", err)
  }
  err = enc.Encode(P{1024, 2048, 1000, "BG "})
  if err != nil {
    log.Fatal("encode error:", err)
  }

  //   dec               
  //         ,      (&network)         Q   q    
  var q Q
  err = dec.Decode(&q)
  if err != nil {
    log.Fatal("decode error 1:", err)
  }
  fmt.Printf("%q: {%d, %d}
", q.Name, *q.X, *q.Y) err = dec.Decode(&q) if err != nil { log.Fatal("decode error 2:", err) } fmt.Printf("%q: {%d, %d}
", q.Name, *q.X, *q.Y) }

実行効果:
$ go run simple-encoder-decoder.go
"xxbandy.github.io": {6, 6}
"BG ": {1024, 2048}

2.カスタムEncodeおよびDecodeメソッドツールによる値の転送
インタフェースによる構造体変数のプライベート変数の変換
package main
import (
  "bytes"
  "encoding/gob"
  "fmt"
  "log"
)

// Vector           ,         ,        `gob` 
//    BinaryMarshal/BinaryUnmarshal                    .
//           `encoding`  
//             `GobEncode/GobDecoder`  

type Vector struct {
  x, y, z int
}

// Vector MarshalBinary  
func (v Vector) MarshalBinary() ([]byte, error) {
  // A simple encoding: plain text.
  //             
  var b bytes.Buffer
  fmt.Fprintln(&b, v.x, v.y, v.z)
  return b.Bytes(), nil
}

// Vector UnmarshalBinary          ,        
func (v *Vector) UnmarshalBinary(data []byte) error {
  b := bytes.NewBuffer(data)
  _, err := fmt.Fscanln(b, &v.x, &v.y, &v.z)
  return err
}


//       encoding decoding       
func main() {
  //   buffer        
  var network bytes.Buffer

  //         encoder       
  enc := gob.NewEncoder(&network)
  //  Vector                 ,           
  //   :  Vector                MarshalBinary UnmarshalBinary  
  err := enc.Encode(Vector{3, 4, 5})
  if err != nil {
    log.Fatal("encode:", err)
  }

  //        (decoder)      
  dec := gob.NewDecoder(&network)
  var v Vector
  err = dec.Decode(&v)
  if err != nil {
    log.Fatal("decode:", err)
  }
  fmt.Println(v)

}

出力例:
$ go run gob-EncoderDecoder.go
{3 4 5}

3.gobパケットを使用してインタフェースタイプのデータを転送するgobパケットを使用してインタフェースタイプデータを符号化、復号、伝送するには、gob.Register(value interface{})を使用して指定されたタイプデータを登録する必要がある.
/**
 * @File Name: gob-interface.go
 * @Author: xxbandy @http://xxbandy.github.io
 * @Email:
 * @Create Date: 2018-03-12 14:03:10
 * @Last Modified: 2018-03-12 14:03:23
 * @Description:
 */
package main

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

type Point struct {
  X, Y int
}

//         
func (p Point) Hypotenuse() float64 {
  return math.Hypot(float64(p.X), float64(p.Y))
}

//         ,          ,        
type Pythagoras interface {
  Hypotenuse() float64
}

//                   
//                           
func main() {
  //         
  var network bytes.Buffer

  //      encoder decoder         
  //                      
  // func Register(value interface{})
  gob.Register(Point{})

  //     encoder     
  enc := gob.NewEncoder(&network)
  for i := 1; i <= 3; i++ {
    interfaceEncode(enc, Point{3 * i, 4 * i})
  }

  //     decoder       
  dec := gob.NewDecoder(&network)
  for i := 1; i <= 3; i++ {
    result := interfaceDecode(dec)
    fmt.Println(result.Hypotenuse())
  }

}

// interfaceEncode              encoder   
func interfaceEncode(enc *gob.Encoder, p Pythagoras) {
  //                    ,     
  //                     ,          p,           
  err := enc.Encode(&p)
  if err != nil {
    log.Fatal("encode:", err)
  }
}

// interfaceDecode                     
//     Pythagoras       
func interfaceDecode(dec *gob.Decoder) Pythagoras {
  // decode                  (Point{}     gob.Register()         )
  //                   
  var p Pythagoras
  err := dec.Decode(&p)
  if err != nil {
    log.Fatal("decode:", err)
  }
  return p
}
$ go run gob-interface.go
5
10
15