Io.Writer in Go - 初学者试图理解它们

why*_*yme 10 go writer

作为Go的初学者,我有理解的问题io.Writer.

我的目标:获取一个结构并将其写入json文件.

方法:
- 用于encoding/json.Marshal将我的结构转换为字节
- 将这些字节提供给os.FileWriter

这就是我的工作方式:

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)
}
Run Code Online (Sandbox Code Playgroud)

阅读本文后,我将程序更改为:

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)
}
Run Code Online (Sandbox Code Playgroud)

在我看来,第一个例子对初学者来说更直接,更容易理解......但我觉得第二个例子是实现目标的Go惯用方法.

问题:
1.以上假设是否正确(第二个选项是Go idiomatic)?
2.上述选项有区别吗?哪个选项更好?
3.实现同一目标的其他方式?

谢谢,

WM

Nev*_*ore 9

使用第二种方法的好处是,如果您传递的是Writer接口,则可以传递任何实现的东西Write - http.ResponseWriter例如,不仅是文件,而是传递stdout os.Stdout,而不更改struct方法.

您可以在io演练包中看到这个方便的博客文章.作者认为,作为参数读者和作者的传递使您的代码更加灵活,部分原因是因为许多函数使用ReaderWriter接口.

当你开始使用Go more时,你会注意到标准库倾斜了多少ReaderWriter接口,并且可能会欣赏它:)

所以这个功能(重命名):

// 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
}
Run Code Online (Sandbox Code Playgroud)

会写入文件,http 响应,用户的Stdout,甚至是简单的字节缓冲区 ; 使测试更简单.

我改名是因为它做了什么; 也就是说,此函数采用Person结构和:

  1. 将结构编组为json表示
  2. 把json写成a Writer
  3. 返回编组/写入引起的任何错误

还有一件事,你可能会对Writer是什么感到困惑,因为它不是数据类型,而是一个接口 - 这是一种数据类型的行为,一种类型实现的预定义方法.Write()那么,实现该方法的任何东西都被认为是作家.

对于初学者来说,这可能有点难以掌握,但是在线有很多资源可以帮助理解接口(并且ReadWriters是一些更常见的接口,以及Error()(例如所有错误)).