Golang向下转型结构列表

时间:2015-07-01 15:27:28

标签: go

我希望能够不那么严格地解组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中做这种事情的惯用方法。其他第三方解决方案可能存在,但我不会立即对它们感兴趣,因为我经常在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应该是FileReader,因为它嵌入了yamlcms.Page。

1 个答案:

答案 0 :(得分:1)

编辑:我忘记了切片界面不能那样工作。您需要分配一个新切片,将所有页面转换为FileReaders,调用该函数并将其转换回来。

另一种可能的解决方案是重构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 }
}

原始答案:

Go中没有继承或强制转换等内容。更喜欢设计中的构图和界面。在您的情况下,您可以重新定义yamlcms.ReadDir以接受界面FileReader

type FileReader interface {
    ReadFile(file string) error
}

yamlcms.Pagemain.Page都会实现这一点,因为后者会嵌入前者。