简体   繁体   English

Golang 向下转换结构列表

[英]Golang downcasting list of structs

I want to be able to unmarshal yaml files less rigidly.我希望能够不那么严格地解组 yaml 文件。 That is, my library has a predefined number of options the yaml file must have.也就是说,我的库具有 yaml 文件必须具有的预定义数量的选项。 Then, the user should be able to extend this to include any custom options.然后,用户应该能够扩展它以包含任何自定义选项。

Here is what I have这是我所拥有的

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

Here is the yamlcms package:这是 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
}

There is a compiler issue here:这里有一个编译器问题:

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

My main intent in this question is to learn the idiomatic way of doing this kind of thing in Go.我在这个问题上的主要目的是学习在 Go 中做这种事情的惯用方式。 Other 3rd-party solutions may exist but I am not immediately interested in them because I have problems like this frequently in Go having to do with inheritance, etc. So along the lines of what I've presented, how can I best (idiomatically) accomplish what I am going for?可能存在其他 3rd-party 解决方案,但我对它们并没有立即感兴趣,因为我在 Go 中经常遇到这样的问题,与继承等有关。所以按照我所介绍的,我怎样才能最好(惯用地)完成我的目标?

EDIT:编辑:

So I've made some changes as suggested.所以我按照建议做了一些改变。 Now I have this:现在我有这个:

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
}

However, I still get a similar compiler error:但是,我仍然收到类似的编译器错误:

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

Even though main.Page should be a FileReader because it embeds yamlcms.Page.尽管 main.Page 应该是一个 FileReader,因为它嵌入了 yamlcms.Page。

EDIT: I forgot that slices of interfaces don't work like that.编辑:我忘记了接口片不是那样工作的。 You'd need to allocate a new slice, convert all pages to FileReaders , call the function, and convert them back.您需要分配一个新切片,将所有页面转换为FileReaders ,调用该函数,然后将它们转换回来。

Another possible solution is refactoring yamlcms.ReadDir to return the contents of the files, so that they could be unmarshaled later:另一种可能的解决方案是重构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 }
}

The original answer:原答案:

There are no such things as inheritance or casting in Go. Go 中没有继承或强制转换之类的东西。 Prefer composition and interfaces in your designs.在您的设计中更喜欢组合和界面。 In your case, you can redefine your yamlcms.ReadDir to accept an interface, FileReader .在您的情况下,您可以重新定义yamlcms.ReadDir以接受接口FileReader

type FileReader interface {
    ReadFile(file string) error
}

Both yamlcms.Page and main.Page will implement this, as the latter embeds the former. yamlcms.Pagemain.Page都将实现这一点,因为后者嵌入了前者。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM