du42561
du42561
2013-07-24 19:35

模板和自定义功能; 恐慌:功能未定义

  • IT行业问题
  • 计算机技术
  • it技术
  • 编程语言问答
  • 互联网问答
已采纳

Using html/template I am trying to use one of my own functions inside a template. Unfortunately I am unable to use the function map feature of go's templates. All I get is the following error:

% go run test.go
panic: template: tmpl.html:5: function "humanSize" not defined
[...]

The reduced testcase looks as follows (test.go):

package main

import (
    "html/template"
    "io/ioutil"
    "net/http"
    "strconv"
)

var funcMap = template.FuncMap{
    "humanSize": humanSize,
}
var tmplGet = template.Must(template.ParseFiles("tmpl.html")).Funcs(funcMap)

func humanSize(s int64) string {
    return strconv.FormatInt(s/int64(1000), 10) + " KB"
}

func getPageHandler(w http.ResponseWriter, r *http.Request) {
    files, _ := ioutil.ReadDir(".")
    if err := tmplGet.Execute(w, files); err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
    }
}

func main() {
    http.HandleFunc("/", getPageHandler)
    http.ListenAndServe(":8080", nil)
}

And I have the following simple template (tmpl.html):

<html><body>
    {{range .}}
    <div>
        <span>{{.Name}}</span>
        <span>{{humanSize .Size}}</span>
    </div>
    {{end}}
</body></html>

This is go 1.1.1.

  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 复制链接分享
  • 邀请回答

2条回答

  • doukong9982 doukong9982 8年前

    IIRC, template functions map must be defined by .Funcs before parsing the template. The below code seems to work.

    package main
    
    import (
            "html/template"
            "io/ioutil"
            "net/http"
            "strconv"
    )
    
    var funcMap = template.FuncMap{
            "humanSize": humanSize,
    }
    
    const tmpl = `
    <html><body>
        {{range .}}
        <div>
            <span>{{.Name}}</span>
            <span>{{humanSize .Size}}</span>
        </div>
        {{end}}
    </body></html>`
    
    var tmplGet = template.Must(template.New("").Funcs(funcMap).Parse(tmpl))
    
    func humanSize(s int64) string {
            return strconv.FormatInt(s/int64(1000), 10) + " KB"
    }
    
    func getPageHandler(w http.ResponseWriter, r *http.Request) {
            files, err := ioutil.ReadDir(".")
            if err != nil {
                    http.Error(w, err.Error(), http.StatusInternalServerError)
                    return
            }
    
            if err := tmplGet.Execute(w, files); err != nil {
                    http.Error(w, err.Error(), http.StatusInternalServerError)
            }
    }
    
    func main() {
            http.HandleFunc("/", getPageHandler)
            http.ListenAndServe(":8080", nil)
    }
    
    点赞 评论 复制链接分享
  • douniao8687 douniao8687 3年前

    The solution is to have same names in the function New() and Parse‌​Files() a suggested by @user321277

    var tmplGet = template.Must(template.New("base.html").Funcs(funcMap).Parse‌​Files("tmpl/base.htm‌​l", "tmpl/get.html"))
    
    点赞 评论 复制链接分享

为你推荐