io.Writer in Go - beginner trying to understand them

go, writer

Solution

The benefit of using the second method is that if you are passing a `Writer` interface, you can pass anything which implements `Write` -- that is not only a file but a `http.ResponseWriter`, for example, or stdout `os.Stdout`, without changing the struct methods.

You can see this handy blog post on the package io walkthrough. The author makes the case that passing as parameter readers and writers makes your code more flexible, in part because so many functions use the `Reader` and `Writer` interface.

As you come to use Go more, you'll notice how much the standard library leans on `Reader` and `Writer` interfaces, and probably come to appreciate it :)

So this function (renamed):

// writes json representation of Person to Writer
func (p *Person) WriteJson(w io.Writer) error {
    b, err := json.Marshal(*p)
    if err != nil {
        return err
    }
    _, err = w.Write(b)
    if err != nil {
        return err
    }
    return err
}

Would write to a File, http Response, a user's Stdout, or even a simple byte Buffer; making testing a bit simpler.

I renamed it because of what is does; that is, this function takes a `Person` struct and:

- Marshals the struct into a json representation

- Writes the json to a `Writer`

- Returns any errors arising from marshalling/writing

One more thing, you might be confused as to what a Writer is, because it is not a data type, but rather an interface -- that is a behavior of a data type, a predefined method that a type implements. Anything that implements the `Write()` method, then, is considered a writer.

This can be a bit difficult for beginners to grasp at first, but there are lots of resources online to help understand interfaces (and `ReadWriters` are some of the more common interfaces to encounter, along with `Error()` (ei. all errors)).

Problem

As a beginner in Go, I have problems understanding `io.Writer`. My target: take a struct and write it into a json file. Approach: - use `encoding/json.Marshal` to convert my struct into bytes - feed those bytes to an `os.File` Writer This is how I got it working: ``` package main import ( "os" "encoding/json" ) type Person struct { Name string Age uint Occupation []string } func MakeBytes(p Person) []byte { b, _ := json.Marshal(p) return b } func main() { gandalf := Person{ "Gandalf", 56, []string{"sourcerer", "foo fighter"}, } myFile, err := os.Create("output1.json") if err != nil { panic(err) } myBytes := MakeBytes(gandalf) myFile.Write(myBytes) } ``` After reading this article, I changed my program to this: ``` package main import ( "io" "os" "encoding/json" ) type Person struct { Name string Age uint Occupation []string } // Correct name for this function would be simply Write // but I use WriteToFile for my understanding func (p *Person) WriteToFile(w io.Writer) { b, _ := json.Marshal(*p) w.Write(b) } func main() { gandalf := Person{ "Gandalf", 56, []string{"sourcerer", "foo fighter"}, } myFile, err := os.Create("output2.json") if err != nil { panic(err) } gandalf.WriteToFile(myFile) } ``` In my opinion, the first example is a more straightforward and easier to understand for a beginner... but I have the feeling that the 2nd example is the Go idiomatic way of achieving the target. Questions: 1. is above assumption correct (that 2nd option is Go idiomatic) ? 2. Is there a difference in the above options ? Which option is better ? 3. other ways to achieve the same target ? Thank you, WM

Original source