如何将结构编码回字节缓冲区

I am making a API request and the response I get back is a bytes.Buffer. I then json decode that into my struct:

resp, status, err := // api call that calls http client do and returns byte buff

result := MyStruct{}
err = json.NewDecoder(response).Decode(&result)

I know want to take my struct, result, and gzip it.

Should I be using a json decoder to get the value back?

I want to then take that decoded json so I can then gzip it eventually.

Also, I am confused between a byte array, bytebuffer and then these readers. Is this hierarchy like java?

I am a bit confused by your question but maybe this helps a bit:

Assuming you would use the standard http.Client your HTTP call would be done via Client.Do which returns an *http.Response.

You can read the response body from the Body field which is of type io.ReadCloser. This is actually just an interface that combines the io.Reader and io.Closer interface. If you know the response is json you can now create a json.Decoder using json.NewDecoder which accepts any io.Reader.

Its important to keep in mind that all types implicitly implement io.Reader by having the following function defined on them:

Read(p []byte) (n int, err error)

Just as the *http.Response Body field is an io.Reader any bytes.Buffer implements io.Reader because it implements the Buffer.Read function.

In contrast a []byte (byte array) is a scalar type that does not implement any functions on its own. Therefore []byte does not implement io.Reader so you can not just pass this into json.NewDecoder. If you want to decode JSON from a byte array/slice you should probably just use json.Unmarshal or create a bytes.Buffer from your []byte using bytes.NewBuffer and then again pass that to the json.Decoder.

The same concepts apply for encoding JSON back but this time instead of an io.Reader you need an io.Writer and a json.Encoder.

io.Reader and io.Writer are interfaces specifying object behaviour regardless of it implementation. bytes.Buffer is data structure implementing both io.Reader and io.Writer. array is just core language data structure similar with others languages have. Most interfaces advantage is you can operate with them uniformly despite underlying implementations. For example io library has func TeeReader(r Reader, w Writer) Reader which returns a Reader that writes to w what it reads from r. You can use it to gzip response as you read and decode it.

SomeWriter, err := os.OpenFile("some/File", os.O_WRONLY, os.ModePerm ) //gzip to file for example
gzipper := gzip.NewWriter(SomeWriter) //but can be any Writer
tee := io.TeeReader(response, gzipper)
//and then
err = json.NewDecoder(tee).Decode(&result)

If you want to store your struct as json, the simplest way is usually to use json.Marshal(), as in:

b, err := json.Marshal(&myStruct)

b will in this case be a byte slice ([]byte). This can later be gzipped using the gzip package. For instance, to gzip the bytes to a file, you could use:

f, _ := os.Create("/tmp/s.gz")
defer f.Close()

w := gzip.NewWriter(f)
w.Write(b)
w.Close()

If you want to, you can bypass creating the byte slice by using json.Encoder.Encode() directly instead.

f, _ := os.Create("/tmp/s.gz")
defer f.Close()

w := gzip.NewWriter(f)
json.NewEncoder(w).Encode(&myStruct)
w.Close()

Depending on where you want to store or send the gzipped json, you can replace the parameter f used in gzip.NewWriter(f) to be any object that implements io.Writer. For instance, you can send the gzipped response using http.ResponseWriter directly in a handler:

func MyHandler(w http.ResponseWriter, r *http.Request) {
    myStruct := ...          // Get struct from somewhere
    gz := gzip.NewWriter(w)
    json.NewEncoder(gz).Encode(&myStruct)
    gz.Close()
}