Golang结构体使用注意事项和细节

结构体的特点

package main

import "fmt"

//定义一个线段Line包含两个端点,每个端点都有一个坐标Point

type Point struct{
	x int
	y int
}

type Line struct{
	a Point
	b Point
}

type Line2 struct{
	a *Point
	b *Point
}

func main() {
	l1 := Line{Point{2, 4}, Point{6, 6}}
	//l1的两个端点在内存中的地址
	fmt.Printf(" l1端点a结构体的内存地址是:%p\n l1端点b结构体的内存地址是:%p\n", &l1.a, &l1.b)
	//l1的两个端点的四个值在内存中的地址
	fmt.Printf(" l1端点a的x坐标的内存地址是:%p\n l1端点a的y坐标的内存地址是:%p\n l1端点b的x坐标的内存地址是:%p\n l1端点b的y坐标的内存地址是:%p\n", &l1.a.x, &l1.a.y, &l1.b.x, &l1.b.y)
	fmt.Println()
	l2 := Line2{&Point{10, 20}, &Point{30, 40}}
	//l2的两个端点在内存中的地址(端点是指针,这里说的是指针自己的地址)
	fmt.Printf(" l2端点a结构体的内存地址是:%p\n l2端点b结构体的内存地址是:%p\n", &l2.a, &l2.b)
	//l2的两个端点在指向的地址
	fmt.Printf(" l2端点a结构体指向的地址是:%p\n l2端点b结构体指向的地址是:%p\n", l2.a, l2.b)
	//l2的两个端点的四个值在内存中的地址
	fmt.Printf(" l2端点a的x坐标的内存地址是:%p\n l2端点a的y坐标的内存地址是:%p\n l2端点b的x坐标的内存地址是:%p\n l2端点b的y坐标的内存地址是:%p\n", &(*l2.a).x, &l2.a.y, &l2.b.x, &l2.b.y)
	//fmt.Println()
}
//运行结果如下
 l1端点a结构体的内存地址是:0xc0000180c0
 l1端点b结构体的内存地址是:0xc0000180d0
 l1端点a的x坐标的内存地址是:0xc0000180c0
 l1端点a的y坐标的内存地址是:0xc0000180c8
 l1端点b的x坐标的内存地址是:0xc0000180d0
 l1端点b的y坐标的内存地址是:0xc0000180d8

 l2端点a结构体的内存地址是:0xc000010200
 l2端点b结构体的内存地址是:0xc000010208
 l2端点a结构体指向的地址是:0xc000016060
 l2端点b结构体指向的地址是:0xc000016070
 l2端点a的x坐标的内存地址是:0xc000016060
 l2端点a的y坐标的内存地址是:0xc000016068
 l2端点b的x坐标的内存地址是:0xc000016070
 l2端点b的y坐标的内存地址是:0xc000016078

一、结构体内存结构特点
1) 结构体的所有字段在内存中是连续的,例如l1的两个端点a、b中的4个值
2) l2有两个*Point类型,这两个类型本身的地址是联系的(指针类型自己的地址)
3) l2有两个*Point类型,这两个指针指向的地址不一定联系(但是在我的实验中总是连续的)

type A struct {
   Num int
}

type B struct {
   Num int
}

func main() {
   var a A
   var b B
   // a = b  这种写个会报错
   a = A(b)  //讲b强转为A类型并赋值给a,可以成功的原因是结构体A和B有完全相同的字段
   fmt.Println(a, b)
}

二、结构体是用户单独定义的类型,和其他类型进行转换时,需要有完全相同的字段。

type Student struct {
   Num int
}

type Stu Student

func main() {
   var stu1 Student
   var stu2 Stu
   // stu1 = stu2  这种写个会报错
   stu1 = Student(stu2)  //讲stu2强转为Student类型并赋值给stu1
   fmt.Println(stu1, stu12)
}

三、结构体进行type重新定义(相当于取别名),Golang认为是新的数据类型,但是相互之间可以强转换。

type Stu struct {
	Name string `json:"name1"`
	Age int `json:"age1"`
	Address string `json:"add1"`
}

func main() {
	stu1 := Stu{"小张", 18, "北京市朝阳区"}
	//将stu1变量序列换为json格式字符串
	student1, err := json.Marshal(stu1) //json.Marshal返回两个值([]byte, error),json.Marshal使用了反射
	if err != nil {
		fmt.Println("json处理错误", err)
	} else {
		fmt.Print("student1", string(student1)) //json.Mashal返回的student1是个切片,需要转换为string
	}
}
//不加 `json:"name1"`、`json:"age1"`、`json:"add1"`运行结果如下
student1{"Name":"小张","Age":18,"Address":"北京市朝阳区"}
//假设tag运行结果如下
student1{"name1":"小张","age1":18,"add1":"北京市朝阳区"}

四、结构体的每个字段上,可以写上一个tag,该tag可以通过反射机制获取,常见的使用场景就是序列化和反序列化。

共有 0 条评论

Top