golang结构体中使用tag标记
简介
我们可以在结构体的字段后面,添加一些对该字段的说明(元信息meta),程序通过反射解析这些信息并使用。
语法结构
`key:"value" key:"value"`
反引号括起来,key不加双引号,value加双引号,多个值中间用空格分开
快速入门
package main
import (
"fmt"
"reflect"
)
func main() {
type S struct {
F string `species:"gopher" color:"blue"`
}
//实例化结构体,在这里没有使用到,所以空实例化
s := S{}
//使用反射获得结构体的type类型
st := reflect.TypeOf(s)
//拿到第一个字段
field := st.Field(0)
//拿到tag里面的东西
fmt.Println(field.Tag.Get("color"), field.Tag.Get("species"))
}
运行结果:
[Running] go run "e:\golang开发学习\go_pro\main.go"
blue gopher
[Done] exited with code=0 in 1.234 seconds
常见应用
应用json编码
package main
import (
"encoding/json"
"fmt"
"log"
"os"
"time"
)
//一般我们字段名都是大写的,但是我们json里面都是小写的,这里就可以通过tag来使用小写来知道大写的字段
type User struct {
Name string `json:"name"`
Password string `json:"password"`
CreatedAt time.Time `json:"createdAt"`
}
func main() {
u := &User{
Name: "Psych",
Password: "123456",
CreatedAt: time.Now(),
}
out, err := json.MarshalIndent(u, "", " ")
if err != nil {
log.Println(err)
os.Exit(1)
}
fmt.Println(string(out))
}
运行结果:
[Running] go run "e:\golang开发学习\go_pro\main.go"
{
"name": "Psych",
"password": "123456",
"createdAt": "2022-09-09T16:58:24.0876915+08:00"
}
[Done] exited with code=0 in 1.136 seconds
应用xml编码
package main
import (
"encoding/xml"
"fmt"
"os"
)
func main() {
type Address struct {
City, State string
}
type Person struct {
XMLName xml.Name `xml:"person"`
Id int `xml:"id,attr"` //attr代表属性
FirstName string `xml:"name>first"`
LastName string `xml:"name>last"` //>代表子节点
Age int `xml:"age"`
Height float32 `xml:"height,omitempty"`
Married bool
Address
Comment string `xml:"comment"`
}
v := &Person{Id: 13, FirstName: "Wong", LastName: "Psych", Age: 18}
v.Comment = "注释."
v.Address = Address{"四川", "成都"}
output, err := xml.MarshalIndent(v, "", " ")
if err != nil {
fmt.Printf("error:%v\n", err)
}
_, err = os.Stdout.Write(output)
if err != nil {
return
}
}
运行结果:
[Running] go run "e:\golang开发学习\go_pro\main.go"
<person id="13">
<name>
<first>Wong</first>
<last>Psych</last>
</name>
<age>18</age>
<Married>false</Married>
<City>四川</City>
<State>成都</State>
<comment>注释.</comment>
</person>
[Done] exited with code=0 in 1.248 seconds
应用form表单绑定
可以写多个tag标签,使用空格分开
type Channel struct {
Id uint64 `form:"id" gorm:"primaryKey"`
Title string `form:"title" gorm:"title"`
Slug string `form:"slug" gorm:"slug"`
Content string `form:"content" gorm:"content"`
Status int `form:"status" gorm:"status"`
Weight int `form:"weight" gorm:"weight"`
}
gin框架form和数据绑定
package main
import "C"
import (
"github.com/gin-gonic/gin"
"net/http"
)
type Login struct {
//form:表单中的name一般是小写的id,json:前后端分离返回给前端的参数,binding:字段校验
User string `form:"user" json:"user" binding:"required"`
Password string `form:"password" json:"password" binding:"required"`
}
func main() {
router := gin.Default()
// 绑定 JSON ({"user":"manu","password":"123"})
router.POST("/loginJSON", func(c *gin.Context) {
var json Login
if err := c.ShouldBindJSON(&json); err == nil {
if json.User == "manu" && json.Password == "123" {
c.JSON(http.StatusOK, gin.H{"status": "成功登录"})
} else {
c.JSON(http.StatusUnauthorized, gin.H{"status": "未授权"})
}
} else {
C.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
}
})
//HTML form (user=manu&password=123)
router.POST("/loginForm", func(c *gin.Context) {
var form Login
if err := c.ShouldBind(&form); err == nil {
if form.User == "manu" && form.Password == "123" {
c.JSON(http.StatusOK, gin.H{"status": "成功登录"})
} else {
c.JSON(http.StatusUnauthorized, gin.H{"status": "未授权"})
}
} else {
C.JSON(http.StatusBadRequest, gin.H{"error": err.Error})
}
})
}