结构体实例化的几种方式
Go语言中没有“类”的概念,也不支持“类”的继承等面向对象的概念。(继承,多态,封装)
Go语言中通过结构体的内嵌再配合接口比面向对象具有更高的扩展性和灵活性。
1. 基本实例化(方法1)
只有当结构体实例化时,才会真正地分配内存(其实也就是使用new),也就是必须实例化后才能使用结构体的字段。
结构体本身也是一种类型,我们可以像声明内置类型一样使用 var 关键字声明结构体类型。
type person struct {
name string
city string
age int
}
func main() {
var p1 person
p1.name = "张三"
p1.city = "北京"
p1.age = 18
fmt.Printf("p1=%v\n", p1) // p1={张三 北京 18}
fmt.Printf("p1=%#v\n", p1) // p1=main.person{name:"张三", city:"北京", age:18}
var p2 person = person{
name: "lucas",
city: "beijing",
age: 0,
}
fmt.Println(p2)
}
2. new实例化(方法2)
-
我们还可以通过使用 new 关键字对结构体进行实例化,得到的是结构体的地址
-
从打印的结果中我们可以看出 p2 是一个结构体指针。
-
注意:在 Golang 中支持对结构体指针直接使用.来访问结构体的成员。
-
p2.name = "张三" 其实在底层是 (*p2).name = "张三"
type person struct {
name string
city string
age int
}
func main() {
var p2 = new(person)
p2.name = "张三"
p2.age = 20
p2.city = "北京"
fmt.Printf("p2=%#v \n", p2) //p2=&main.person{name:"张三", city:"北京", age:20}
}
3. 键值对初始化(方法3 结构体能够使用指针就使用指针)
type person struct {
name string
city string
age int
}
func main() {
p4 := &person{
name: "zhangsan",
city: "北京",
age: 18,
}
// p4=&main.person{name:"zhangsan", city:"北京", age:18}
fmt.Printf("p4=%#v\n", p4)
}
结构体方法和接收者
1. 结构体说明
在 go 语言中,没有类的概念但是可以给类型(结构体,自定义类型)定义方法。所谓方法就是定义了接收者的函数。
Go语言中的方法(Method)是一种作用于特定类型变量的函数。这种特定类型变量叫做接收者(Receiver)。接收者的概念就类似于其他语言中的this或者 self。
方法的定义格式如下:
func (接收者变量 接收者类型) 方法名(参数列表) (返回值) {
函数体
}
2. 结构体方法和接收者
给结构体 Person 定义一个方法打印 Person 的信息
type Person struct {
name string
age int8
}
func (p Person) printInfo() {
fmt.Printf("姓名:%v 年龄:%v", p.name, p.age) // 姓名:小王子 年龄:25
}
func main() {
p1 := Person{
name: "小王子",
age: 25,
}
p1.printInfo() // 姓名:小王子 年龄:25
}
3. 值类型和指针类型接收者
实例1:给结构体 Person 定义一个方法打印 Person 的信息
值类型的接收者
-
当方法作用于值类型接收者时,Go 语言会在代码运行时将接收者的值复制一份。
-
在值类型接收者的方法中可以获取接收者的成员值,但修改操作只是针对副本 ,无法修改接收者变量本身。
指针类型的接收者
-
指针类型的接收者由一个结构体的指针组成
-
由于指针的特性,调用方法时修改接收者指针的任意成员变量,在方法结束后,修改都是有效的。
-
这种方式就十分接近于其他语言中面向对象中的 this 或者 self
方法大部分时候是自己处理自己的数据,总结如下:
encoding-json包 struct与json
比如我们 Golang 要给 App 或者小程序提供 Api 接口数据,这个时候就需要涉及到结构体和Json 之间的相互转换。
-
GolangJSON 序列化是指把结构体数据转化成 JSON 格式的字符串
-
Golang JSON 的反序列化是指把 JSON 数据转化成 Golang 中的结构体对象
-
Golang 中的序列化和反序列化主通过 "encoding/json" 包中的 json.Marshal() 和json.Unmarshal()方法实现
-
struct转Json字符串
type Student struct {
ID int
Gender string
name string //私有属性不能被 json 包访问
Sno string
}
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":"男","Sno":"s0001"}
}
-
Json字符串转struct
type Student struct {
ID int
Gender string
Name string
Sno string
}
func main() {
var jsonStr = `{"ID":1,"Gender":"男","Name":"李四","Sno":"s0001"}`
var student Student //定义一个student实例
err := json.Unmarshal([]byte(jsonStr), &student)
if err != nil {
fmt.Printf("unmarshal err=%v\n", err)
}
// 反序列化后 student=main.Student{ID:1, Gender:"男", Name:"李四", Sno:"s0001"}
student.Name="张三"
fmt.Printf("反序列化后 student=%#v student.Name=%v \n", student, student.Name)
}
2. struct tag
1)Tag标签说明
-
Tag 是结构体的元信息,可以在运行的时候通过反射的机制读取出来。
-
Tag 在结构体字段的后方定义,由一对反引号包裹起来
具体的格式如下:
key1:"value1" key2:"value2"
-
结构体 tag 由一个或多个键值对组成。键与值使用冒号分隔,值用双引号括起来。
-
同一个结构体字段可以设置多个键值对 tag,不同的键值对之间使用空格分隔。
注意事项:
- 为结构体编写 Tag 时,必须严格遵守键值对的规则。
- 结构体标签的解析代码的容错能力很差,一旦格式写错,编译和运行时都不会提示任何错误,通过反射也无法正确取值。例如不要在 key 和 value 之间添加空格。
Tag结构体转化Json字符串
type Student struct {
ID int `json:"id"` //通过指定 tag 实现 json 序列化该字段时的 key(表示在做json操作的时候,用json指定的字段名)
Gender string `json:"gender"`
Name string
Sno string
}
func main() {
var s1 = Student{
ID: 1,
Gender: "男",
Name: "李四",
Sno: "s0001",
}
// main.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字符串转成Tag结构体
type Student struct {
ID int `json:"id"` //通过指定 tag 实现 json 序列化该字段时的 key
Gender string `json:"gender"`
Name string
Sno string
}
func main() {
var s2 Student
var str = `{"id":1,"gender":"男","Name":"李四","Sno":"s0001"}`
err := json.Unmarshal([]byte(str), &s2)
if err != nil {
fmt.Println(err)
}
// main.Student{ID:1, Gender:"男", Name:"李四", Sno:"s0001"}
fmt.Printf("%#v", s2)
}