Go提供了很好的HTML模板功能,但对我而言,确保我的应用程序中的模板始终可以使用某些字段非常重要。一个很好的例子是标题字段,需要在每个HTML页面上显示。
鉴于以下几页:
Home
Register
Contact
我可能会为模板系统创建以下对象:
HomePage
结构
RegisterPage
结构
ContactPage
struct
是否有建议的方法来确保每个页面的结构具有某些可用的字段?
理想情况下,我会通过多态实现这一点,但Go中没有正式支持。替代方案embedding似乎没有任何强制执行,即所有子结构可以嵌入父结构但不必必须
如果我没有清楚地表达我的问题,请告诉我。
答案 0 :(得分:3)
执行模板不会对参数强制执行任何操作,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
包来检查值是否为结构值以及是否嵌入了另一个接口。嵌入式结构出现并且可以像普通字段一样访问,例如使用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:}