os.Exit(code),当code为0,表示成功;非0,表示失败。
此时会产生下面结果:
回到log.Fatal函数,在该函数中会先调用Output,随后调用os.Exit(1),那么产生的结果就是:
回到panic函数,会产生以下几个核心点:
在进行单元测试时,我们通常使用:
go test -v
这个只会在当前文件夹下生效,对于子目录不生效,那如果想生效所有子目录呢?也就是当前整个项目单测,则需要使用./...
go test ./... -v
这个在测试自己的单元测试是否通过是非常重要的!
我们在使用切片时,通常需要对当前切片进行清空操作,如何实现呢?
[a我们可以采用[:0]或者nil的方式。]
猜猜下面会输出什么:
arr := []int{1, 2, 3}
a := arr[:]
a = nil
fmt.Println(a, len(a), cap(a))
b := arr[:]
b = b[:0]
fmt.Println(b, len(b), cap(b))
1) nil
当赋值为nil,垃圾回收器会自动回收原有数据。
所以,第一次的Println会输出,[] 0 0。
2)[:0]
如果我们还需要保存原有的切片内存,最佳方式是re-slice,第二次输出,[] 0 3。
template实现了数据驱动的用于生成文本输出的模版。
在工作中有个需求,就是写个sql去对库进行插入、更新等操作。
那通常的方式是去拼接一个sql语句,但是这样会拼接出错。诸如下面这样:
sq := "select * from user where id = " + id
当字段太多就需要拼接很多了,此时容易出错,而模版变可以方便的生成sql字符串,再配上正则简直屌爆。
先来聊聊模版可以做什么,然后再回顾到本文的sql需求上。
1) 变量
通过创建一个变量,使用模版的New创建一个模版,并解析出传递进去的字符串。
str := "world"
tmpl, err := template.New("hello world").Parse("hello, {{.}}\n")
if err != nil {
panic(err)
}
err = tmpl.Execute(os.Stdout, str)
if err != nil {
panic(err)
}
当然,还可以传递结构体哦。像下面这样通过.直接访问结构体成员。
type User struct {
Name string
Id uint
}
func main() {
sweaters := User{"wli", 1}
tmpl, err := template.New("test").Parse("{{.Name}} of {{.Id}}\n")
if err != nil {
panic(err)
}
err = tmpl.Execute(os.Stdout, sweaters)
if err != nil {
panic(err)
}
}
自定义变量,通过$
+变量名方式创建新的变量,方法有参数,后面加参数即可。
注意传递方法时,该方法如果没有返回值直接报panic,模版对返回值有严格要求,第一种是只有一个返回值,第二个是第二个返回值必须是error。
type User struct {
Name string
Id uint
}
func (my *User) SayHello() string { //没参数
return "hello"
}
func (my *User) SayYouName(name string) string { //有参数
return "my name is : " + name
}
func main() {
user := &User{Name: "wli", Id: 1}
tmpl, err := template.New("test").Parse(`
{{$str1 := .Name}}
{{$str2 := .SayHello}}
{{$str3 := .SayYouName .Name}}
{{$str1}} {{$str2}} {{$str3}}`)
if err != nil {
panic(err)
}
err = tmpl.Execute(os.Stdout, user)
if err != nil {
panic(err)
}
}
2) 函数
在变量那里提到了方法传递,当然函数传递也一样。
这里还有Funcs函数与FuncMao将函数添加到模版中,接口:
func (t *Template) Funcs(funcMap FuncMap) *Template
type FuncMap map[string]interface{}
使用如:
funcMap := template.FuncMap{
"SayHello": SayHello,
"SayYouName": SayYouName,
}
name := "hello"
tmpl, err := template.New("test").Funcs(funcMap).Parse("{{SayHello}}\n{{SayYouName .}}\n")
在模版中,还预定义了一些全局函数,可以直接在{{}}中使用。
例如:print、index、len等。
print、printf、println、index、len、call、js、html、or、and、not
使用如:
s := []int{1, 2, 3}
tmpl, err := template.New("test").Parse(`{{printf "%+v\n" .}}{{ len .}}`)
if err != nil {
panic(err)
}
err = tmpl.Execute(os.Stdout, s)
if err != nil {
panic(err)
}
3) range
假设Friends是个数组,里面包含了很多Friend,每个Friend结构为:
type Friend struct {
Fname string
Flag bool
}
我们可以通过range遍历每个Friend。
{{with .Friends}}
{{range .}}
{{$.UserName}} friend name is {{.Fname}}
{{end}}
{{end}}
4) if
只支持bool类型。
{{if .Flag}}
flag
{{else}}
not flag
{{end}}
前面综合例子:
import (
"os"
"text/template"
)
type Friend struct {
Fname string
Flag bool
}
type Person struct {
UserName string
Emails []string
Friends []*Friend
}
func main() {
f1 := Friend{Fname: "f1 name", Flag: false}
f2 := Friend{Fname: "f2 name", Flag: true}
t := template.New("template example")
t, _ = t.Parse(`hello {{.UserName}},
{{range .Emails}}
email = {{.}}
{{end}}
{{with .Friends}}
{{range .}}
{{$.UserName}} friend name is {{.Fname}}
{{if .Flag}}
flag
{{else}}
not flag
{{end}}
{{end}}
{{end}}
`)
p := Person{UserName: "francis",
Emails: []string{"francis@beego.me", "francis@gmail.com"},
Friends: []*Friend{&f1, &f2},
}
t.Execute(os.Stdout, p)
}
最后,回到我们的sql例子。
type User struct {
ID string
UserName string
Age int
Date string
}
t := template.New("userInsertTemplate")
sql := `
select * from user where ID='{{.ID}}'
and date='{{.Date}}'
`
t, err := t.Parse(sql)
record := User{
ID: "123",
Date: "2021-07-08",
}
out := strings.Builder{}
if err := t.Execute(&out, record); err != nil {
return
}
fmt.Println(out.String())
// 去除空格、换行、空白符 匹配一个或多个空白符的正则表达式
spaceReg, _ := regexp.Compile(`\s+`)
sqlQuery := spaceReg.ReplaceAllString(out.String(), " ")
fmt.Println(sqlQuery
到这里便可以输出完整的sql了。
本节完~