模板 object 现场执行
Template object field enforcement
Go 提供了很好的内置 HTML 模板功能,但是对我来说,重要的是我可以确保某些字段始终可用于我的应用程序中的模板。一个很好的例子是标题字段,它需要显示在每个 HTML 页面上。
给定以下页面:
Home
Register
Contact
我可能会为模板系统创建以下 objects:
HomePage
结构
RegisterPage
结构
ContactPage
结构
是否有推荐的方法来确保每个页面的结构都有可用的特定字段?
理想情况下,我会通过多态性来实现这一点,但这在 Go 中并没有得到官方支持。替代方案 embedding 似乎没有任何强制执行,即所有 child 结构 可以 嵌入 parent 结构但不不得不.
如果我没有足够清楚地表达我的问题,请告诉我。
执行模板不会对参数强制执行任何内容,Template.Execute()
接受类型为 interface{}
的值。
您是创建 HomePage
、RegisterPage
和 ContactPage
结构的人。是什么阻止您将 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:}
Go 提供了很好的内置 HTML 模板功能,但是对我来说,重要的是我可以确保某些字段始终可用于我的应用程序中的模板。一个很好的例子是标题字段,它需要显示在每个 HTML 页面上。
给定以下页面:
Home
Register
Contact
我可能会为模板系统创建以下 objects:
HomePage
结构
RegisterPage
结构
ContactPage
结构
是否有推荐的方法来确保每个页面的结构都有可用的特定字段?
理想情况下,我会通过多态性来实现这一点,但这在 Go 中并没有得到官方支持。替代方案 embedding 似乎没有任何强制执行,即所有 child 结构 可以 嵌入 parent 结构但不不得不.
如果我没有足够清楚地表达我的问题,请告诉我。
执行模板不会对参数强制执行任何内容,Template.Execute()
接受类型为 interface{}
的值。
您是创建 HomePage
、RegisterPage
和 ContactPage
结构的人。是什么阻止您将 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:}