本文深入探讨了 Go 语言中模板的使用,特别是 template.FormatterMap 的工作原理,解释了为什么需要包装函数来适配特定的函数签名。同时,还探讨了如何修改 HTTP 处理函数以接受命令行参数,从而提高程序的灵活性和可配置性。
在 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。
原始代码中的 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 的值作为要编码的数据。
注意事项:
完整代码示例:
package main import ( "flag" "fmt" "html/template" "io" "log" "net/http" "net/url" ) var addr = flag.String("addr", ":1718", "http service address") // Q=17, R=18 var 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 语言的模板和作用域/函数的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号