【问题标题】:Template object field enforcement模板对象字段强制执行
【发布时间】:2016-01-03 10:53:48
【问题描述】:

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

鉴于以下页面:
Home
Register
Contact

我可能会为模板系统创建以下对象:
HomePage struct
RegisterPage struct
ContactPage struct

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

理想情况下,我会通过多态来实现这一点,但这在 Go 中不受官方支持。另一种选择,embedding 似乎没有任何强制执行,即所有子结构可以嵌入父结构,但不必必须

如果我的问题表达得不够清楚,请告诉我。

【问题讨论】:

    标签: templates struct go interface embedding


    【解决方案1】:

    执行模板不会对参数强制执行任何操作,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包来检查一个值是否是一个结构值,以及它是否嵌入了另一个接口。嵌入式结构出现并且可以像普通字段一样访问,例如使用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:}
    

    【讨论】:

    • 感谢您详细而有见地的回答!
    猜你喜欢
    • 1970-01-01
    • 2015-02-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-21
    • 2020-05-31
    • 2013-07-14
    • 2015-11-13
    相关资源
    最近更新 更多