将接口传递给方法的正确方法

Correct way to pass interfaces to methods

偏好:我是 Golang 的新手并且渴望改进。

所以我正在尝试从 Dave Cheney 的演讲中学习:https://youtu.be/NwEuRO_w8HE?t=812 我们将接口传递给方法以使代码更清晰、更通用。

我在下面实现了一个示例,其中我有一个可以输出到 std.out 或文件的结构。但是,我觉得只制作空结构(在我的示例中称为“打印”和“保存”)有点多余,这样我就可以附加方法。我该如何改进?

package main

import (
    "fmt"
    "io"
    "io/ioutil"
    "log"
)

type file struct {
    data string
}

func (f *file) output(w io.Writer) error {
    len, err := w.Write([]byte(f.data))
    if err != nil {
        return err
    } else {
        log.Println("Bytes Out: ", len)
        return nil
    }
}

type print struct{}

func (print *print) Write(p []byte) (n int, err error) {
    return fmt.Printf("%s\n", p)
}

type save struct{}

func (s *save) Write(p []byte) (n int, err error) {
    err = ioutil.WriteFile("./dat1", []byte(p), 0644)
    if err != nil {
        return -1, err
    }
    return len(p), nil
}
func main() {
    f := file{"test"}
    s := save{}
    p := print{}

    f.output(&s)
    f.output(&p)
}

您的意图不明确,但回答您最初的问题:如何将函数作为接口值传递?

您可以创建一个类似适配器的类型来实现 io.Writer,并且当它的 Write() 方法被调用时,它会转发给您选择的函数。一个典型的例子是 http.HandlerFunc: it's a function type that implements http.Handler,因此当需要 http.Handler 实现时可以传递一个函数。

对于 io.Writer 适配器,它可能如下所示:

type WriteFunc func(p []byte) (n int, err error)

func (w WriteFunc) Write(p []byte) (n int, err error) {
    return w(p)
}

如果你有这样的功能:

func PrintWrite(p []byte) (n int, err error) {
    return fmt.Printf("%s\n", p)
}

func SaveWrite(p []byte) (n int, err error) {
    err = ioutil.WriteFile("./dat1", []byte(p), 0644)
    if err != nil {
        return -1, err
    }
    return len(p), nil
}

您可以像这样 io.Writer 使用它们:

f.output(WriteFunc(PrintWrite))
f.output(WriteFunc(SaveWrite))

Go Playground 上试用。

此处不需要 printsave 类型。你有一个方法,output,需要一个 io.Writer;关键在于您可以 任何作者 传递它。 stdout 和 files 都是写入器,所以这里的其他一切都是不必要的。你可以:

func main() {
    f := file{"test"}

    fp,err := os.Create("./dat1")
    if err != nil {
        panic(err)
    }
    f.output(fp)  // This writes to a file
    f.output(os.Stdout)  // This writes to stdout
}