io.Writer in Go – beginner trying to understand them

huangapple go评论72阅读模式
英文:

io.Writer in Go - beginner trying to understand them

问题

作为Go语言的初学者,我在理解io.Writer方面遇到了问题。

我的目标是将一个结构体写入到一个JSON文件中。

实现方法如下:

  • 使用encoding/json.Marshal将结构体转换为字节
  • 将这些字节传递给os.File的写入器(Writer)

以下是我实现的代码示例:

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

在阅读了这篇文章之后,我将我的程序修改为以下形式:

package main

import (
    "io"
    "os"
    "encoding/json"
)

type Person struct {
    Name       string
    Age        uint
    Occupation []string
}

// 这个函数的正确名称应该是Write,但为了方便理解,我使用了WriteToFile
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)
}

在我看来,第一个示例对于初学者来说更直观、更容易理解... 但我有一种感觉,第二个示例是使用Go语言的惯用方式来实现目标。

问题:

  1. 上述假设正确吗(第二个选项是Go语言的惯用方式)?
  2. 上述选项有什么区别?哪个选项更好?
  3. 是否有其他实现相同目标的方法?

谢谢!

WM

英文:

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

答案1

得分: 25

使用第二种方法的好处是,如果你传递一个Writer接口,你可以传递任何实现了Write方法的东西,不仅仅是文件,还可以是http.ResponseWriter,或者是标准输出os.Stdout,而不需要改变结构体的方法。

你可以查看这篇有用的博文,介绍了io包的使用方法:io walkthrough。作者认为,将读取器和写入器作为参数传递可以使你的代码更加灵活,部分原因是因为很多函数使用了ReaderWriter接口。

当你开始更多地使用Go时,你会注意到标准库有多么依赖于ReaderWriter接口,并且可能会对此有所欣赏 io.Writer in Go – beginner trying to understand them

所以这个函数(重命名为):

// 将Person的json表示写入到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
}

可以将数据写入到文件http响应、用户的标准输出,甚至是一个简单的字节缓冲区,这样测试就会变得更简单。

我将它重命名是因为它的功能;也就是说,这个函数接受一个Person结构体,并且:

  1. 将结构体序列化为json表示
  2. 将json写入到**Writer**
  3. 返回序列化/写入过程中出现的任何错误

还有一件事,你可能会对Writer是什么感到困惑,因为它不是一种数据类型,而是一个接口,也就是一种数据类型的行为,一个预定义的方法,一个类型实现的方法。因此,任何实现了Write()方法的东西都被认为是一个写入器。

对于初学者来说,这可能有点难以理解,但是有很多在线资源可以帮助理解接口(ReadWriterError()也是一些常见的接口,错误处理也是如此)。

英文:

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 io.Writer in Go – beginner trying to understand them

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:

  1. Marshals the struct into a json representation
  2. Writes the json to a Writer
  3. Returns any errors arising from marshalling/writing

<hr>

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

huangapple
  • 本文由 发表于 2017年5月5日 05:41:46
  • 转载请务必保留本文链接:https://go.coder-hub.com/43793229.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定