首页 > 其他分享 >Go的Struct结构体和(Json Form tag)

Go的Struct结构体和(Json Form tag)

时间:2022-10-03 11:00:42浏览次数:88  
标签:name Form fmt struct json Json type string Struct


Go的Struct结构体和(Json Form tag)

1.Struct

1.1 定义

Go的Struct结构体和(Json Form tag)_字段

使用struct关键字可以定义一个结构体,结构体中的成员,称为结构体的字段或属性。

type Member struct {
id int
name, email string
gender, age int
}

type Member struct {
id int
name string
email string
gender int
age int
}

type 和 struct 都是关键字,type表示类型,struct表示结构体。

说明结构体是一个复合类型。

上面的代码中,我们定义了一个包含5个字段的结构体,可以看到,相同类型​​name​​​和​​email​​​、​​gender​​​和​​age​​在同一行中定义,但比较好的编程习惯是每一行只定义一个字段。

1.2 声明

直接定义变量,这个使用方式并没有为字段赋初始值,因此所有字段都会被自动赋予自已类型的零值,比如​​name​​的值为空字符串"",age的值为0。

var m1 Member//所有字段均为空值

var m2 = Member{1,"小明","[email protected]",1,18} // 简短变量声明方式:m2 := Member{1,"小明","[email protected]",1,18}

var m3 = Member{id:2,"name":"小红"}// 简短变量声明方式:m3 := Member{id:2,"name":"小红"}

Go的Struct结构体和(Json Form tag)_序列化_02


另一个实例

func Older(p1, p2 Person) (person , int){
if p1.age > p2.age {
return p1, p1.age - p2.age
}
return p2, p1.age - p2.age
}

func main(){
var tom Person
tom.name, tom.age = "tom", 20

bob := Person{name: "bob", age: 22}

old, diff := Older(tom, bob)

fmt.Printf("%s %d", old.name, diff)

}

1.3 访问字段

通过变量名,使用逗号​​(.)​​,可以访问结构体类型中的字段,或为字段赋值,也可以对字段进行取址(&)操作。

fmt.Println(m2.name)//输出:小明
m3.name = "小花"
fmt.Println(m3.name)//输出:小花

age := &m3.age
*age = 20
fmt.Println(m3.age)//20

1.4 指针结构体

Go的Struct结构体和(Json Form tag)_序列化_03

Go的Struct结构体和(Json Form tag)_json_04


另一个实例

type Command struct {
Name string // 指令名称
Var *int // 指令绑定的变量
Comment string // 指令的注释
}

var version int = 1

cmd := &Command{}

cmd.Name = "version"
cmd.Var = &version
cmd.Comment = "show version"

1.5 可见性

上面的例子中,我们定义结构体字段名首字母是小写的,这意味着这些字段在​​包外不可见​​,因而无法在其他包中被访问,只允许包内访问。

下面的例子中,我们将Member声明在member包中,而后在main包中创建一个变量,但由于结构体的字段包外不可见,因此无法为字段赋初始值,无法按字段还是按索引赋值,都会引发panic错误

package member
type Member struct {
id int
name string
email string
gender int
age int
}

package main

fun main(){
var m = member.Member{1,"小明","[email protected]",1,18}//会引发panic错误
}

Go的Struct结构体和(Json Form tag)_字段_05

1.6 Tag

Go的Struct结构体和(Json Form tag)_字段_06

1.7 特点

Go的Struct结构体和(Json Form tag)_字段_07

1.8 方法

Go的Struct结构体和(Json Form tag)_字段_08


Go的Struct结构体和(Json Form tag)_字段_09

1.9 组合

组合,可以理解为定义一个结构体中,其字段可以是其他的结构体,这样,不同的结构体就可以共用相同的字段。

type Animal struct {
Name string //名称
Color string //颜色
Height float32 //身高
Weight float32 //体重
Age int //年龄
}
//奔跑
func (a Animal)Run() {
fmt.Println(a.Name + "is running")
}
//吃东西
func (a Animal)Eat() {
fmt.Println(a.Name + "is eating")
}

type Cat struct {
a Animal
}

func main() {
var c = Cat{
a: Animal{
Name: "猫猫",
Color: "橙色",
Weight: 10,
Height: 30,
Age: 5,
},
}
fmt.Println(c.a.Name)
c.a.Run()
}

可以看到,我们定义Cat结构体时,可以把Animal结构体作为Cat的字段。


另一个实例

//Animal 动物
type Animal struct {
name string
}

func (a *Animal) move() {
fmt.Printf("%s会动!\n", a.name)
}

//Dog 狗
type Dog struct {
Feet int8
*Animal //通过嵌套匿名结构体实现继承
}

func (d *Dog) wang() {
fmt.Printf("%s会汪汪汪~\n", d.name)
}

func main() {
d1 := &Dog{
Feet: 4,
Animal: &Animal{ //注意嵌套的是结构体指针
name: "乐乐",
},
}
d1.wang() //乐乐会汪汪汪~
d1.move() //乐乐会动!
}

1.9.1 匿名字段

当我们创建结构体时,字段可以只有类型,而没有字段名。这样的字段称为匿名字段(Anonymous Field)。习惯上匿名字段叫内嵌,具名字段叫组合.

上面的例子,我们看到,把Animal结构体作为Cat的字段时,其变量名为a,所以我们访问Animal的方法时,语法为​​c.a.Run()​​,这种通过叶子属性访问某个字段类型所带的方法和字段用法非常繁琐。

Go语言支持直接将类型作为结构体的字段,而不需要取变量名,这种字段叫​​匿名字段​​,如:

type Lion struct {
Animal //匿名字段
}

func main(){
var lion = Lion{
Animal{
Name: "小狮子",
Color: "灰色",
},
}
lion.Run()
fmt.Println(lion.Name)
}

通过上面例子,可以看到,通过匿名字段组合其他类型,而后访问匿名字段类型所带的方法和字段时,不需要使用叶子属性,非常方便。


结构体允许其成员字段在声明时只有类型没有字段名,这种没有名字的字段就称为匿名字段。

//Person 结构体Person类型
type Person struct {
string
int
}

func main() {
p1 := Person{
"pprof.cn",
18,
}
fmt.Printf("%#v\n", p1) //main.Person{string:"pprof.cn", int:18}
fmt.Println(p1.string, p1.int) //pprof.cn 18

}

匿名字段默认采用类型名作为字段名,由于结构体要求字段名称必须唯一,因此一个结构体中同种类型的匿名字段只能有一个。


1.9.2 同名问题

从上面的例子可以看出来,struct 不仅可以将struct作为匿名字段,自定义类型、内置类型都可以作为匿名字段,也可以进行相应的函数操作。

这里我们有个问题,Person上有一个name属性,如果Student上也有一个name属性,那么我们怎么办呢?其实在go里面,最外层的属性具有有限的访问权限,当你通过Student.name访问的时候是访问Student上的属性。同理,我们可以通过Student.Person访问Person上的属性,如:

type Human struct {
name stirng
age int
phone string
}
type Employee struct {
Human
phone string
}
func main(){
bob := Employee{Human{name: "Bob", age: 12, phone: "777444}, "3322"}
// 访问 Employee的phone属性
fmt.Println("bob phone is ", bob.phone) // bob phone is 3322
// 访问 Human的phone属性
fmt.Println("bob's person phone is ", bob.Human.phone)
}

1.10 自定义构造函数

Go的Struct结构体和(Json Form tag)_序列化_10

1.11 结构体比较

如果结构体的全部成员都是可以比较的,那么结构体也是可以比较的,那样的话两个结构体将可以使用 == 或 != 运算符进行比较,但不支持 > 或 < 。

func main() {
s1 := Student{name:"Luffy", age:18 }
s2 := Student{name:"Luffy", age:18 }

fmt.Println("s1 == s2", s1 == s2) //s1 == s2 true
fmt.Println("s1 != s2", s1 != s2) //s1 != s2 false
}

2.JSON tag序列化

2.1 格式说明

Go的Struct结构体和(Json Form tag)_序列化_11

Go的Struct结构体和(Json Form tag)_java_12

常用于对struct结构体字段进行json序列化

Go的Struct结构体和(Json Form tag)_序列化_13

2.tag里面加上omitempy,可以在序列化的时候忽略0值或者空值

package main

import (
"encoding/json"
"fmt"
)

// Product _
type Product struct {
Name string `json:"name"`
ProductID int64 `json:"product_id,omitempty"`
Number int `json:"number"`
Price float64 `json:"price"`
IsOnSale bool `json:"is_on_sale,omitempty"`
Amount int `json:"amount"`
}

func main() {
p := &Product{}
p.Name = "Xiao mi 6"
p.IsOnSale = false
p.Number = 10000
p.Price = 2499.00
p.ProductID = 0
data, _ := json.Marshal(p)
fmt.Println(string(data))
}

结果

{"name":"Xiao mi 6","number":10000,"price":2499,"amount":0}

// 值为false,0或者空字符串的ProductID和IsOnSalebool都没有出现在最后的json串里。

3.有些时候,我们在序列化或者反序列化的时候,可能结构体类型和需要的类型不一致,这个时候可以指定tag的type支持

package main

import (
"encoding/json"
"fmt"
)

// Product _
type Product struct {
Name string `json:"name"`
ProductID int64 `json:"product_id,string"`
Number int `json:"number,string"`
Price float64 `json:"price,string"`
IsOnSale bool `json:"is_on_sale,string"`
}

type ProductV2 struct {
Name string `json:"name"`
ProductID int64 `json:"product_id"`
Number int `json:"number"`
Price float64 `json:"price"`
IsOnSale bool `json:"is_on_sale"`
}

func main() {
var data = `{"name":"Xiao mi 6","product_id":"10","number":"10000","price":"2499","is_on_sale":"true"}`
p := &Product{}
err := json.Unmarshal([]byte(data), p)
fmt.Printf("[have type] err:%v,p:%+v\n", err, p)

p2 := &ProductV2{}
err = json.Unmarshal([]byte(data), p2)
fmt.Printf("[no type] err:%v,p:%+v\n", err, p2)
}

结果

[have type] err:<nil>,p:&{Name:Xiao mi 6 ProductID:10 Number:10000 Price:2499 IsOnSale:true}
[no type] err:json: cannot unmarshal string into Go struct field ProductV2.product_id of type int64,p:&{Name:Xiao mi 6 ProductID:0 Number:0 Price:0 IsOnSale:false}

其中json的type如下:

bool, for JSON booleans
float64, for JSON numbers
string, for JSON strings
[]interface{}, for JSON arrays
map[string]interface{}, for JSON objects
nil for

若要在被嵌套结构体整体为空时使其在序列化结果中被忽略,不仅要在被嵌套结构体字段后加上json:“fileName,omitempty”,还要将其改为结构体指针。如:

package main

import (
"encoding/json"
"fmt"
)

type BodyInfo struct {
Weight float64
Height float64
}

type Student struct {
Name string `json:"name"`
Age int64
*BodyInfo `json:"bodyinfo,omitempty"` // 要使用指针
}

func main() {
s1 := Student{
Name: "jack",
Age: 20,
}

data, _ := json.Marshal(s1)
fmt.Println(string(data))
}

//结果
{"name":"jack","Age":20}

3.Form Tag

Gin中提供了模型绑定,将表单数据和模型进行绑定,方便参数校验和使用。

模型绑定:

// 表单数据
type LoginForm struct {
UserName string `form:"username"`
Password string `form:"password"`
Email string `form:"email"`
}
// model 或 service 层Model
type Email struct {
Email string
Password string
}


func EmailLogin (c *gin.Context) {
var email LoginForm
if err := c.ShouldBind(&email); err != nil {
...
}
// 获取表单数据局
args := Email {
Email: email.Email,
Password: email.Password,
}
// 对参数进行后续使用
...
}

通过 form:“email” 对表单email数据进行绑定。然后通过Bind()、ShouldBind()等方法获取参数值。


3.参考文章

​传送门1​

​传送门2​

​传送门3​

​传送门4​


JSON序列化部分

​传送门5​

​传送门6​


标签:name,Form,fmt,struct,json,Json,type,string,Struct
From: https://blog.51cto.com/u_15326986/5729948

相关文章

  • 多点DLT (Direct Linear Transformation) 算法
    阅读前可以先参看上一篇代数视觉博客:四点DLT(DierctLinearTransformation)算法对于大于4个点的数据点来进行DLT算法变换,如果数据点的标注都十分准确,那么将所有......
  • 四点DLT (Direct Linear Transformation) 算法
    \(\mathrm{x}_{i}\)表示变化前的齐次坐标\(\mathbf{x}_{i}^{\prime}\)表示变化后的齐次坐标我们需要求到一个\(3\times3\)的变换矩阵\(\mathrm{H}\),使得\[\math......
  • Vision Transformer和MLP-Mixer联系和对比
    VisionTransformer和MLP-Mixer是深度学习领域最新的两个体系结构。他们在各种视觉任务中都非常成功。视觉VisionTransformer的性能略好于MLP-Mixers,但更复杂。但是这两个......
  • MapStruct使用(二)
    批量转换#编写convertimportorg.mapstruct.factory.Mappers;importjava.util.List;@MapperpublicabstractclassCarConvert{publicstaticCarConvert......
  • 拼接Json数据可以直接提交到AB框架Rest服务端(主从表)
    //=============================================================================== let_this=this letsalesorderdata=_this.params _this.salesorder.a......
  • 使用JAVA代码实现POST发送application/x-www-form-urlencoded请求
    前言在实际开发过程中,我们经常是使用的POST发送application/json;charset=utf-8格式请求,但是有时候接口会设计成application/x-www-form-urlencoded,这就需要我们随机应变,......
  • Js中对Json对象的操作
    1,将json对象转换为json字符串(json序列话)JSON.stringify(对象);2,将json字符串转换为json对象(json反序列话)JSON.parse(字符串);3,js对json对象操作(增删改) <scriptt......
  • 关于Axios传json对象给后端,后端将json在转换为pojo对象,
    Controller使用@ResquestParam注解,形参并不直接写pojo对象,而是Map<String,Object>对象,然后使用其get(“key”)方法得到前端作为url参数传递过来的json格式的object对象,使用......
  • MapStruct使用(一)
    官网不同的convert解决方案名字描述mapstruct基于jsr269实现在编译期间生成代码,性能高,精细控制,解耦orika能够精细控制,解耦org.springframewo......
  • C#: WindowsForm窗体切换以及窗体的关闭
    Form1窗体代码:usingSystem;usingSystem.Collections.Generic;usingSystem.ComponentModel;usingSystem.Data;usingSystem.Drawing;usingSystem.Linq;usingSystem.......