Go-struct
1.关于 Golang 结构体
- Golang 中没有“类”的概念,Golang 中的结构体和其他语言中的类有点相似。和其他面向对象语言中的类相比,Golang 中的结构体具有更高的扩展性和灵活性。
- Golang 中的基础数据类型可以表示一些事物的基本属性,但是当我们想表达一个事物的全部或部分属性时,这时候再用单一的基本数据类型就无法满足需求了,
- Golang 提供了一种自定义数据类型,可以封装多个基本数据类型,这种数据类型叫结构体,英文名称 struct。
- 也就是我们可以通过 struct 来定义自己的类型了。
2.结构体定义初始化的几种方法
2.1结构体的定义
使用 type 和 struct 关键字来定义结构体,具体代码格式如下
type 类型名 struct {
字段名 字段类型
字段名 字段类型
…
}
/*
注意:结构体首字母可以大写也可以小写,大写表示这个结构体是公有的,
在其他的包里面 可以使用。小写表示这个结构体是私有的,只有这个包里面才能使用。
*/
type person struct {
sex string
// 可以写在一行
name,city string
age int
}
2.2六种实例化方法
package main
import "fmt"
/*
注意:结构体首字母可以大写也可以小写,大写表示这个结构体是公有的,
在其他的包里面 可以使用。小写表示这个结构体是私有的,只有这个包里面才能使用。
*/
type person struct {
sex string
// 可以写在一行
name, city string
age int
}
func main() {
// 1.结构体实例化(第一种方法)
var p1 person
p1.age = 22
p1.name = "GJH"
p1.city = "北京"
p1.sex = "男"
fmt.Println(p1) //{男 GJH 北京 22}
fmt.Println(p1.sex) // 男
//2.第二种实例化
var p2 = new(person)
p2.sex = "男"
p2.name = "GJH"
fmt.Println(p2) // &{男 GJH 0} p2 是一个结构体指针
//3.使用&对结构体进行取地址操作相当于对该结构体类型进行了一次 new 实例化操作。
p3 := &person{}
p3.sex = "女"
p3.name = "LYL"
fmt.Println(p3) //&{女 LYL 0}
//4.结构体实例化(第四种方法) 键值对初始化
p4 := person{
sex: "男",
age: 22, //注意:最后一个属性的","要加上
}
fmt.Println(p4) //{男 22}
//5.结构体实例化(第五种方法) 结构体指针进行键值对初始化
p5 := &person{
name: "码云",
}
fmt.Println(p5) //&{ 码云 0}
//6.结构体实例化(第六种方法) 使用值的列表初始化
/*
初始化结构体的时候可以简写,也就是初始化的时候不写键,直接写值:
使用这种格式初始化时,需要注意:
1.必须初始化结构体的所有字段。
2.初始值的填充顺序必须与字段在结构体中的声明顺序一致。
3.该方式不能和键值初始化方式混用
4.字段数量一致
*/
p7 := &person{
"男",
"马化腾",
"北京",
22,
}
fmt.Println(p7) //&{男 马化腾 北京 22}
}
3.结构体属性类型使用
package main
import "fmt"
/*
结构体的字段类型可以是:基本数据类型、也可以是切片、Map 以及结构体
如果结构体的字段类型是: 指针,slice,和map的零值都是 nil ,即还没有分配空间
如果需要使用这样的字段,需要先make,才能使用.
*/
type Person struct {
Name string
Age int
Hobby []string
map1 map[string]string
}
func main() {
var p Person
p.Name = "张三"
p.Age = 20
p.Hobby = make([]string, 2, 6)
p.Hobby[0] = "写代码"
p.Hobby[1] = "打篮球"
p.map1 = make(map[string]string)
p.map1["address"] = "北京"
p.map1["phone"] = "1324325325"
fmt.Printf("%#v\n", p)
//main.Person{Name:"张三", Age:20, Hobby:[]string{"写代码", "打篮球", "睡觉"}, map1:map[string]string{"address":"北京", "phone":"1324325325"}}
fmt.Printf("%v", p.Hobby) //[写代码 打篮球 睡觉]
}
4.结构体嵌套
package main
import "fmt"
type User1 struct {
Name string
Age int
ccc string
User2 User2 // 这就是结构体的嵌套 获取的时候要加上结构体名字 User2.属性
User3 // 这就是结构体的匿名嵌套 匿名嵌套 获取的属性的时候 会自己在结构体内寻找
}
type User2 struct {
aaa string
bbb int
ccc string
}
type User3 struct {
Hobby string
school string
AddTime string
ccc string
}
func main() {
var u User1
u.Name = "GJH"
u.Age = 22
u.ccc = "ccc"
/*
错误写法
u.aaa = "asdasd" // 如果结构体不是写的匿名嵌套 要加上结构体名字进行获取属性
*/
// 正确写法
u.User2.aaa = "aaa"
u.User2.bbb = 11111
u.User2.ccc = "ccc2"
// 直接修改User3的AddTime
u.school = "清华"
u.AddTime = "2021-03-27"
u.User3.ccc = "ccc3"
fmt.Println(u) // {GJH 22 ccc {aaa 11111 ccc2} { 清华 2021-03-27 ccc3}}
/*
注意:
1.当访问结构体成员时会先在结构体中查找该字段,找不到再去匿名结构体中查找。
2.当有相同属性的时候 访问要加上结构体的名字 :u.User2.ccc = "ccc2"
*/
}
5.结构体方法
/*
结构体可以描述现实生活中的任何事物,生活中的任何事物都可以当做结构体对象
我们可以把客观事物封装成结构体 :
汽车
汽车有属性:颜色 大小 重量 发动机 轮胎 ...
汽车行为 也叫方法: run 跑
小狗
属性:颜色 大小 品种 性别 ..
行为:叫 、闻一闻 舔一舔 咬一咬
电风扇
属性: 颜色 大小 高低...
行为:转动
人也是一个结构体对象:
属性: 名字 年龄 性别 ...
行为:工作 运动 ..
*/
package main
import "fmt"
type Person struct {
Name string
Age int
Sex string
height int
}
func (p Person) PrintInfo() {
fmt.Printf("姓名:%v 年龄:%v\n", p.Name, p.Age)
}
func main() {
var p1 = Person{
Name: "张三",
Age: 20,
Sex: "男",
}
p1.PrintInfo() //姓名:张三 年龄:20
var p2 = Person{
Name: "李四",
Age: 30,
Sex: "男",
}
p2.PrintInfo() //姓名:李四 年龄:30
p1.PrintInfo() //姓名:张三 年龄:20
}
6.结构体继承
package main
import "fmt"
//父亲结构体
type Animal struct {
Name string
}
func (a Animal) run() {
fmt.Printf("%v 在运动\n", a.Name)
}
//子结构体
type Dog struct {
Age int
Animal //结构体嵌套 继承
}
func (d Dog) wang() {
fmt.Printf("%v 在旺旺\n", d.Name)
}
func main() {
var d = Dog{
Age: 20,
Animal: Animal{
Name: "阿奇",
},
}
d.run() //阿奇 在运动
d.wang() //阿奇 在旺旺
}
7.结构体&JSON互相转换
Golang JSON 序列化是指把结构体数据转化成 JSON 格式的字符串
Golang JSON 的反序列化是指把 JSON 数据转化成 Golang 中的结构体对象
Golang 中 的 序 列 化 和 反 序 列 化 主 要 通 过 "encoding/json" 包 中 的 json.Marshal() 和 json.Unmarshal() 方法实现
package main
import (
"encoding/json"
"fmt"
)
type Student struct {
ID int
Gender string
Name string //私有属性不能被 json 包访问
Sno string
}
func main() {
// 结构体转JSON
var s1 = Student{
ID: 1,
Gender: "男",
Name: "李四",
Sno: "s0001",
}
//fmt.Printf("%#v\n", s1)
var s, _ = json.Marshal(s1)
jsonStr := string(s)
fmt.Println(jsonStr) //{"ID":1,"Gender":"男","Name":"李四","Sno":"s0001"}
// JSON 转结构体
var jsonStr2 = `{"ID":1,"Gender":"男","Name":"李四","Sno":"s0001"}`
//定义一个 Monster 实例
var student Student
err := json.Unmarshal([]byte(jsonStr2), &student)
if err != nil {
fmt.Printf("unmarshal err=%v\n", err)
}
fmt.Printf("反序列化后 student=%#v student.Name=%v \n", student, student.Name)
//反序列化后 student=main.Student{ID:1, Gender:"男", Name:"李四", Sno:"s0001"} student.Name=李四
}
结构体Tag
结构体标签:可以指定属性转换之后的字段名(起别名)
package main
import (
"encoding/json"
"fmt"
)
type Student struct {
ID int `json:"id"` //通过指定 tag 实现 json 序列化该字段时的 key
Gender string `json:"gender"`
Name string `json:"name"`
Sno string `json:"sno"`
}
func main() {
var s1 = Student{
ID: 1,
Gender: "男",
Name: "李四",
Sno: "s0001",
}
//fmt.Printf("%#v\n", s1) //main.Student{ID:1, Gender:"男", Name:"李四", Sno:"s0001"}
var s, _ = json.Marshal(s1)
jsonStr := string(s)
fmt.Println(jsonStr) //{"id":1,"gender":"男","name":"李四","sno":"s0001"}
}