
本文深入探讨了 Go 语言中模板的使用,特别是 template.FormatterMap 的工作原理,解释了为什么需要包装函数来适配特定的函数签名。同时,还探讨了如何修改 HTTP 处理函数以接受命令行参数,从而提高程序的灵活性和可配置性。
理解 template.FormatterMap 和函数签名
在 Go 语言的 html/template 包中,FormatterMap 类型定义了一个字符串到格式化函数的映射。这些格式化函数用于在模板执行期间处理特定类型的数据。FormatterMap 的定义如下:
type FormatterMap map[string]func(io.Writer, interface{}, string)
这意味着 FormatterMap 中的每个值都必须是一个具有 func(io.Writer, interface{}, string) 签名的函数。
现在,考虑 template.HTMLEscape 函数的签名:
func HTMLEscape(w io.Writer, b []byte)
这个函数接受一个 io.Writer 和一个字节切片 []byte 作为参数,并将字节切片进行 HTML 转义后写入 io.Writer。
由于 HTMLEscape 的签名与 FormatterMap 所需的签名不匹配,因此不能直接将 HTMLEscape 函数赋值给 FormatterMap 中的一个键。
这就是为什么需要一个包装函数 UrlHtmlFormatter 的原因。这个包装函数接收 io.Writer、interface{} 和 string 作为参数,并在其内部调用 HTMLEscape 函数。通过这种方式,UrlHtmlFormatter 适配了 FormatterMap 所需的函数签名,同时允许我们使用 HTMLEscape 函数来处理模板中的数据。
以下是 UrlHtmlFormatter 函数的示例:
func UrlHtmlFormatter(w io.Writer, v interface{}, fmt string) { template.HTMLEscape(w, []byte(http.URLEscape(v.(string))))}
在这个函数中,v.(string) 将 interface{} 类型的值转换为字符串。然后,http.URLEscape 函数对字符串进行 URL 编码,并将结果转换为字节切片。最后,template.HTMLEscape 函数对字节切片进行 HTML 转义,并将结果写入 io.Writer。
修改 HTTP 处理函数以接受命令行参数
原始代码中的 QR 函数接受一个 http.Conn 和一个 http.Request 作为参数:
func QR(c *http.Conn, req *http.Request) { templ.Execute(req.FormValue("s"), c)}
要修改这个函数以接受命令行参数,可以使用 flag 包来定义和解析命令行标志。
首先,在 main 函数中定义一个命令行标志:
var text = flag.String("text", "", "Text to encode in QR code")
这个标志名为 text,默认值为空字符串,描述为 “Text to encode in QR code”。
然后,在 main 函数中调用 flag.Parse() 来解析命令行标志:
func main() { flag.Parse() http.HandleFunc("/", QR) // 使用 http.HandleFunc err := http.ListenAndServe(*addr, nil) if err != nil { log.Fatal("ListenAndServe:", err) // 使用 log.Fatal }}
现在,可以修改 QR 函数以使用命令行标志的值:
func QR(w http.ResponseWriter, req *http.Request) { var data string if *text != "" { data = *text } else { data = req.FormValue("s") } templ.Execute(data, w)}
在这个修改后的 QR 函数中,首先检查命令行标志 text 是否为空。如果不为空,则使用命令行标志的值作为要编码的数据。否则,使用请求参数 s 的值作为要编码的数据。
注意事项:
需要将 QR 函数的签名更改为 func(w http.ResponseWriter, req *http.Request),以便与 http.HandleFunc 兼容。需要使用 log.Fatal 而不是 log.Exit,以便在发生错误时正确退出程序。需要使用 http.ResponseWriter 作为 templ.Execute 的第二个参数。
完整代码示例:
package mainimport ( "flag" "fmt" "html/template" "io" "log" "net/http" "net/url")var addr = flag.String("addr", ":1718", "http service address") // Q=17, R=18var text = flag.String("text", "", "Text to encode in QR code")var fmap = template.FuncMap{ "html": template.HTMLEscapeString, "url+html": UrlHtmlFormatter,}var templ = template.Must(template.New("qr").Funcs(fmap).Parse(templateStr))func main() { flag.Parse() http.HandleFunc("/", QR) fmt.Println("Server listening on", *addr) err := http.ListenAndServe(*addr, nil) if err != nil { log.Fatal("ListenAndServe:", err) }}func QR(w http.ResponseWriter, req *http.Request) { var data string if *text != "" { data = *text } else { data = req.FormValue("s") } err := templ.Execute(w, data) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) }}func UrlHtmlFormatter(v interface{}) template.HTML { escapedURL := url.QueryEscape(fmt.Sprint(v)) escapedHTML := template.HTMLEscapeString(escapedURL) return template.HTML(escapedHTML)}const templateStr = `QR Link Generator {{if .}}@@##@@
{{.|html}}
{{end}}`
总结:
通过理解 template.FormatterMap 的函数签名要求,我们可以创建包装函数来适配不同的函数。此外,使用 flag 包可以轻松地向 Go 程序添加命令行参数,从而提高程序的灵活性和可配置性。

以上就是使用 Go 语言的模板和作用域/函数的详细内容,更多请关注创想鸟其它相关文章!
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1393350.html
微信扫一扫
支付宝扫一扫