Nil pointer evaluation in template...why? Is there a better strategy?

Viewed 5405

I am attempting to wrap html/template so I am guaranteed to have certain data in my templates (session data for example) in addition to the data I want to render. However, my current approach is...flawed. Here's a simplified example below:

package main

import "fmt"
import "os"
import "html/template"

func main() {
    // Passing nil directly to Execute doesn't render anything for missing struct fields
    fmt.Print("Directly rendering nil\n")
    tmpl, err := template.New("master").Parse("Foo is: {{.Data.Foo}}")
    if err != nil {
        fmt.Printf(err.Error())
        return
    }

    err = tmpl.Execute(os.Stdout, nil)
    if err != nil {
        fmt.Printf(err.Error())
        return
    }

    // Wrapping templates works as long as I supply data...
    fmt.Print("\nRendering Foo\n")
    render(struct {
        Foo string
    }{
        "foo",
    })

    // ...but this breaks.
    fmt.Print("\nRendering nil\n")
    render(nil)
}

func render(data interface{}) {
    allData := struct {
        Session string
        Data    interface{}
    }{
        "sessionData",
        data,
    }

    // Hardcoded template for the example - this could be any arbitrary template
    tmpl, err := template.New("master").Parse("Foo is: {{.Data.Foo}}")
    if err != nil {
        fmt.Printf(err.Error())
        return
    }

    err = tmpl.Execute(os.Stdout, allData)
    if err != nil {
        fmt.Printf(err.Error())
        return
    }
}

I get the following output:

Directly rendering nil
Foo is: 
Rendering Foo
Foo is: foo
Rendering nil
Foo is: template: master:1:15: executing "master" at <.Data.Foo>: nil pointer evaluating interface {}.Foo

So I'm not quite sure what's going on in the first place - why is it that html/template is capable of handling being passed nil, but can't figure out what to do with a nil pointer?

Secondly, is there a better way of approaching this problem?

1 Answers
Related