Golang结构件下推列表

Golang结构件下推列表,go,Go,我希望能够不那么严格地解组yaml文件。也就是说,我的库具有yaml文件必须具有的预定义数量的选项。然后,用户应该能够扩展它以包括任何自定义选项 这是我的 package main import ( "net/http" "yamlcms" "github.com/julienschmidt/httprouter" ) type Page struct { *yamlcms.Page Title string Date string }

我希望能够不那么严格地解组yaml文件。也就是说,我的库具有yaml文件必须具有的预定义数量的选项。然后,用户应该能够扩展它以包括任何自定义选项

这是我的

package main

import (
    "net/http"

    "yamlcms"

    "github.com/julienschmidt/httprouter"
)

type Page struct {
    *yamlcms.Page
    Title string
    Date  string
}

func getBlogRoutes() {
    pages := []*Page{}
    yamlcms.ReadDir("html", pages)
}

// This section is a work in progress, I only include it for loose context
func main() {
    router := httprouter.New()
    //blogRoutes := getBlogRoutes()
    //for _, blogRoute := range *blogRoutes {
    //  router.Handle(blogRoute.Method, blogRoute.Pattern,
    //      func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {})
    //} 
    http.ListenAndServe(":8080", router)
}
以下是yamlcms包:

package yamlcms

import (
    "io/ioutil"
    "os"
    "strings"

    "gopkg.in/yaml.v2"
)

type Page struct {
    Slug string `yaml:"slug"`
    File string `yaml:"file"`
}

func (page *Page) ReadFile(file string) (err error) {
    fileContents, err := ioutil.ReadFile(file)
    if err != nil {
        return
    }   

    err = yaml.Unmarshal(fileContents, &page)
    return
}

func isYamlFile(fileInfo os.FileInfo) bool {
    return !fileInfo.IsDir() && strings.HasSuffix(fileInfo.Name(),     ".yaml")
}

func ReadDir(dir string, pages []*Page) (err error) {
    filesInfo, err := ioutil.ReadDir(dir)
    if err != nil {
        return
    }   

    for i, fileInfo := range filesInfo {
        if isYamlFile(fileInfo) {
            pages[i].ReadFile(fileInfo.Name())
        }   
    }   

    return
}
这里有一个编译器问题:

src/main.go:19: cannot use pages (type []*Page) as type []*yamlcms.Page in argument to yamlcms.ReadDir

我在这个问题上的主要目的是学习在围棋中做这类事情的惯用方法。其他第三方解决方案可能存在,但我对它们不感兴趣,因为我经常遇到类似这样的问题,比如Go与继承有关等。因此,按照我所介绍的思路,我如何才能最好地(习惯地)完成我的目标

编辑:

所以我按照建议做了一些修改。现在我有这个:

type FileReader interface {
    ReadFile(file string) error
}

func ReadDir(dir string, pages []*FileReader) (err error) {
    filesInfo, err := ioutil.ReadDir(dir)
    if err != nil {
        return
    }   

    for i, fileInfo := range filesInfo {
        if isYamlFile(fileInfo) {
            (*pages[i]).ReadFile(fileInfo.Name())
        }   
    }   

    return
}
但是,我仍然会遇到类似的编译器错误:

src/main.go:19: cannot use pages (type []*Page) as type []*yamlcms.FileReader in argument to yamlcms.ReadDir

尽管main.Page应该是一个文件阅读器,因为它嵌入了yamlcms.Page。

编辑:我忘记了接口的片段不是这样工作的。您需要分配一个新的切片,将所有页面转换为
文件阅读器
,调用函数,然后将它们转换回来

另一种可能的解决方案是重构yamlcms.ReadDir,以返回文件的内容,以便以后可以取消对文件的编组:

// In yamlcms.
func ReadYAMLFilesInDir(dir string) ([][]byte, error) { ... }

// In client code.
files := yamlcms.ReadYAMLFilesInDir("dir")
for i := range pages {
    if err := yaml.Unmarshal(files[i], &pages[i]); err != nil { return err }
}
原来的答案是:

在围棋中没有继承或铸造这样的东西。在您的设计中更喜欢组合和界面。在您的情况下,您可以重新定义
yamlcms.ReadDir
以接受接口
FileReader

type FileReader interface {
    ReadFile(file string) error
}

yamlcms.Page
main.Page
都将实现这一点,因为后者嵌入了前者。

“我在Go中经常遇到类似的问题,因为Go中没有继承。我明白了,但我不喜欢的是yamlcms.Page和main.Page都必须实现ReadFile函数。。。除了签名之外,它们将是完全相同的。@eatonphil:不,除了类型之外,它们将是完全相同的签名
Page
实现了
FileReader
,因为它嵌入了
*yamlcms.Page
@eatonphil,这就是你困惑的地方。因为您在
main.Page
main.Page
中嵌入了
yamlcms.Page
,将被识别为实现了该接口。您可以直接从
main.Page
的实例调用ReadFile。实际上,我强烈建议不要重新实现该方法。嵌入不是继承,在嵌入另一个类型的类型中重写方法在我看来是一个非常糟糕的设计。在传统的OOP中,可以将其视为组合,但您不必引用您组合的内容,相反,它的嵌入类型的方法可以直接调用。@JimB我认为eatonphil的意思是,为了解组
main.Page
中的附加字段,它们需要实现相同的方法。@Ainar-G,所以我做了更改,但仍然得到类似的错误-请参阅我的编辑。