
本文深入探讨了 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 = `
<html>
<head>
<title>QR Link Generator</title>
</head>
<body>
{{if .}}
<img src="http://chart.apis.google.com/chart?chs=300x300&cht=qr&choe=UTF-8&chl={{.|url+html}}" />
<br>
{{.|html}}
<br>
<br>
{{end}}
<form action="/" name=f method="GET">
<input maxLength=1024 size=70 name=s value="" title="Text to QR Encode">
<input type=submit value="Show QR" name=qr>
</form>
</body>
</html>
`总结:
通过理解 template.FormatterMap 的函数签名要求,我们可以创建包装函数来适配不同的函数。此外,使用 flag 包可以轻松地向 Go 程序添加命令行参数,从而提高程序的灵活性和可配置性。
以上就是使用 Go 语言的模板和作用域/函数的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号