模板 object 现场执行

Template object field enforcement

Go 提供了很好的内置 HTML 模板功能,但是对我来说,重要的是我可以确保某些字段始终可用于我的应用程序中的模板。一个很好的例子是标题字段,它需要显示在每个 HTML 页面上。

给定以下页面:
Home
Register
Contact

我可能会为模板系统创建以下 objects:
HomePage 结构
RegisterPage 结构
ContactPage 结构

是否有推荐的方法来确保每个页面的结构都有可用的特定字段?

理想情况下,我会通过多态性来实现这一点,但这在 Go 中并没有得到官方支持。替代方案 embedding 似乎没有任何强制执行,即所有 child 结构 可以 嵌入 parent 结构但不不得不.

如果我没有足够清楚地表达我的问题,请告诉我。

执行模板不会对参数强制执行任何内容,Template.Execute() 接受类型为 interface{} 的值。

您是创建 HomePageRegisterPageContactPage 结构的人。是什么阻止您将 BasePage 结构与必填字段一起嵌入?你担心你会忘记它吗?你会在第一次测试时注意到它,我不会担心:

type BasePage struct {
    Title string
    Other string
    // other required fields...
}

type HomePage struct {
    BasePage
    // other home page fields...
}

type RegisterPage struct {
    BasePage
    // other register page fields...
}

如果你想从代码中检查页面结构是否嵌入 BasePage,我推荐另一种方法:接口。

type HasBasePage interface {
    GetBasePage() BasePage
}

实施它的示例HomePage

type HomePage struct {
    BasePage
    // other home page fields...
}

func (h *HomePage) GetBasePage() BasePage {
    return h.BasePage
}

现在显然只有具有 GetBasePage() 方法的页面才能作为 HasBasePage 的值传递:

var page HasBasePage = &HomePage{} // Valid, HomePage implements HasBasePage

如果不想使用接口,可以使用reflect package to check if a value is a struct value and if it embeds another interface. Embedded structs appear and can be accessed like ordinary fields e.g. with Value.FieldByName(),类型名就是字段名。

示例代码使用 reflect 检查值是否嵌入 BasePage:

page := &HomePage{BasePage: BasePage{Title: "Home page"}}

v := reflect.ValueOf(page)
if v.Kind() == reflect.Ptr {
    v = v.Elem()
}
if v.Kind() != reflect.Struct {
    fmt.Println("Error: not struct!")
    return
}
bptype := reflect.TypeOf(BasePage{})
bp := v.FieldByName(bptype.Name()) // "BasePage"
if !bp.IsValid() || bp.Type() != bptype {
    fmt.Println("Error: struct does not embed BasePage!")
    return
}

fmt.Printf("%+v", bp)

输出(在Go Playground上试试):

{Title:Home page Other:}