9-Go基础:结构体与指针

一、结构体

1 - 结构体创建与初始化

  • 结构体概念:结构体是由一系列具有相同类型或不同类型的数据构成的数据集合
  • 结构体应用场景:结构体可以很好地管理一批有联系的数据,使用结构体可以提高程序的易读性
  • 结构体创建语法
type 结构体名 struct {
	成员名 数据类型
	...................
}
  • 结构体初始化的方式
    • 顺序初始化:顺序初始化:每个成员必须初始化,在初始化时,值的顺序与结构体成员的顺序保持一致
    • 指定成员初始化
    • 通过“结构体变量.成员” 完成初始化
func main() {
	// 成员名称前面不能添加var
	type Student struct {
		id   int
		name string
		age  int
		addr string
	}
	// 顺序初始化
	var s Student = Student{101, "张三", 18, "北京"}
	fmt.Println(s)

	// 指定成员初始化,部分初始化
	var s1 Student = Student{name: "李四", age: 18}
	fmt.Println(s1)

	// 通过“结构体变量.成员” 完成初始化
	var stu Student
	stu.id = 102
	stu.name = "老王"
	stu.age = 28
	stu.addr = "北京"
	fmt.Println(stu)
}

2 - 结构体数组

  • 结构体数组定义var 结构体数组名 [下标] 结构体类型
  • 修改结构体数组成员的值结构体数组名[下标].成员=值
  • 结构体数组遍历
    • for…len() 进行遍历
    • for…range 进行遍历
type Student struct {
	id   int
	name string
	age  int
	addr string
}

func main() {
	var arr [3]Student = [3]Student{
		Student{101, "张三", 18, "北京"},
		Student{102, "李四", 18, "北京"},
		Student{103, "王五", 19, "北京"},
	}
	fmt.Println(arr)

	fmt.Println(arr[0])
	fmt.Println(arr[0].age)
	arr[0].age = 20
	fmt.Println(arr)

	// 通过循环来输出结构体数组中的内容。
	for i := 0; i < len(arr); i++ {
		fmt.Println(arr[i].age)
	}

	for k, v := range arr {
		fmt.Println(k)
		fmt.Println(v.age)
	}
}

3 - 结构体切片

  • 结构体切片定义var 结构体切片名 [ ] 结构体类型
  • 修改结构体切片成员的值结构体切片名[下标].成员=值
  • 结构体切片遍历
    • for…len() 进行遍历
    • for…range 进行遍历
  • append函数使用:向结构体切片末尾追加数据
type Student struct {
	id   int
	name string
	age  int
	addr string
}

func main() {

	var s []Student = []Student{
		Student{101, "张三", 18, "北京"},
		Student{102, "李四", 18, "北京"},
	}

	fmt.Println(s[0])
	fmt.Println(s[0].age)
	s[0].age = 20
	fmt.Println(s)

	// 循环遍历
	for i := 0; i < len(s); i++ {
		fmt.Println(s[i].name)
	}
	for k, v := range s {
		fmt.Println(k)
		fmt.Println(v.id)
	}

	// 追加数据
	s = append(s, Student{103, "王五", 20, "北京"})
	fmt.Println(s)
}

4 - 结构体map

  • 结构体map定义:make(map[key的类型]值的类型)
  • 结构体map初始化:map名字[键]=值
  • 结构体map循环遍历:通过for…range方式进行遍历
  • 删除map中的值:delete(map名字,键)
type Student struct {
	id   int
	name string
	age  int
	addr string
}

func main() {
	m := make(map[int]Student)
	m[1] = Student{101, "张三", 18, "北京"}
	m[2] = Student{102, "李四", 18, "北京"}
	fmt.Println(m)
	fmt.Println(m[1])
	fmt.Println(m[1].name)

	delete(m, 2)
	fmt.Println(m)

	for key, value := range m {
		fmt.Println(key)
		fmt.Println(value.age)
	}
}

5 - 结构体作为函数参数

  • 结构体作为函数参数:在函数中修改结构体成员值,不会影响到原结构体
type Student struct {
	id   int
	name string
	age  int
	addr string
}

func main() {
	stu := Student{101, "张三", 18, "北京"}
	PrintDemo(stu)
	fmt.Println(stu) // {101 张三 18 北京}
}

func PrintDemo(stu Student) {
	stu.age = 20
	fmt.Println(stu) // {101 张三 20 北京}
}

二、指针

1 - 指针定义

  • 指针概念:指针也是一个变量,但它是一种特殊的变量,因为它存储的数据不仅仅是一个普通的值(如简单的整数或字符串),而是另一个变量的内存地址

在这里插入图片描述

  • 指针变量定义语法var 指针变量名 *类型
  • 通过指针间接修改变量的值* 指针变量 = 值
func main() {
	var a int = 10
	var p *int
	p = &a
	fmt.Printf("%p\n", &a) // 0xc00000a0a8
	fmt.Printf("%p\n", p)  // 0xc00000a0a8
	fmt.Printf("%p\n", &p) // 0xc000006028
	fmt.Println(*p)        // 10
	*p = 222
	fmt.Println("a=", a) // 222
}

2 - 指针操作注意事项

  • 空指针
func main() {
	var p *int
	fmt.Println(p) // <nil>
}
  • 不要操作没有合法指向的内存
func main() {
	var p *int
	*p = 78
}
  • new函数使用:开辟数据类型对应的内存空间,返回值为数据类型指针
func main() {
	var p *int
	p = new(int)
	*p = 67
	fmt.Println(*p)
}

3 - 指针变量作为函数参数

func main() {
	var num int = 10
	Update(&num)
	fmt.Println(num)
}
func Update(p *int) {
	*p = 60
}

4 - 数组指针

  • 数组指针定义:var 数组指针变量 *[下标] 类型
func main() {
	nums := [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
	var p *[10]int
	p = &nums
	fmt.Println(*p)      // 获取整个数组中的内容,[1 2 3 4 5 6 7 8 9 10]
	fmt.Println((*p)[3]) // []的运算优先级高于*,4
	fmt.Println(p[0])    // 1
	for i := 0; i < len(p); i++ {
		fmt.Println(p[i])
	}

	UpdateArr(p)
	fmt.Println(nums)
}
func UpdateArr(p *[10]int) {
	p[0] = 100
}

5 - 指针数组

  • 指针数组概念:数组元素是指针类型
    • 指针数组指的是一个数组中存储的都是指针(也就是地址)。也就是一个存储了地址的数组
  • 指针数组定义语法:var 数组名 [下标]*类型
  • 指针数组根据具体地址获取对应的值* 指针数组名[下标]
func main() {
	var p [2]*int
	var i int = 10
	var j int = 20
	p[0] = &i
	p[1] = &j
	fmt.Println(p)
	fmt.Println(*p[0]) // 不要加括号
	fmt.Println(*p[1])
	//循环
	for i := 0; i < len(p); i++ {
		fmt.Println(*p[i])
	}
	for k, value := range p {
		fmt.Println(k)
		fmt.Println(*value)
	}
}

6 - 切片指针

  • 切片指针概念:定义指针,指向切片
func main() {
	s := []int{1, 2, 3, 4, 5, 6}
	var p *[]int
	p = &s
	fmt.Println(*p)
	fmt.Println((*p)[0])
	//fmt.Println(p[0]) //错误,这个与数组指针不同

	// 切片指针修改切片的元素
	(*p)[0] = 200
	fmt.Println(s)

	//切片指针遍历
	for i := 0; i < len(*p); i++ {
		fmt.Println((*p)[i])
	}

	for k, value := range *p {
		fmt.Println("k=", k)
		fmt.Println("value=", value)
	}
}

7 - 结构体指针

  • 结构体指针概念:定义指针,指向结构体
  • 结构体指针作为函数:在函数中修改结构体的成员的值,会影响原结构体成员的值
type Student struct {
	id   int
	name string
	age  int
}

func main() {
	stu := Student{101, "张三", 18}
	var p *Student
	p = &stu

	fmt.Println(*p)
	fmt.Println((*p).name)
	fmt.Printf("p.name=%s\n", p.name) // 简化的结构体指针写法

	// 修改结构体中的值
	p.age = 20
	fmt.Println(stu) // {101 张三 20}
	UpdateStruct(p)
	fmt.Println(stu) // {101 张三 21}
}
func UpdateStruct(stu *Student) {
	stu.age = 21
}

8 - 多级指针(简单了解)

func main() {
	var a int = 10
	var p *int //一级指针
	p = &a

	var pp **int
	pp = &p
	**pp = 200
	fmt.Println(a) // 200
}

三、基础加强

1 - 深浅拷贝

  • 浅拷贝:仅仅拷贝的是变量的值,没有对指向的空间进行任何的拷贝
  • 深拷贝:将原有的变量的空间全部拷贝一份(GO语言几乎很少用到)
  • 函数传参是浅拷贝
func main() {
	var num int = 10
	ap := &num
	Update(ap)
	fmt.Println(num)
}
func Update(p *int) {
	*p = 60
}

2 - 切片传参

  • 把切片作为参数可以修改切片中的元素,原因分析
    • 切片的底层本身就是一个结构体
    • Modify传参的时候使用浅拷贝,将结构体的地址传递给了Modify函数
  • 通过append方法对切片进行动态扩容
    • append 当容量不足的时候会动态分配内存,这块内存是一个新的内存
func main() {
	s := make([]int, 5, 5)
	Modify(s)
	fmt.Println(s) // [0 0 0 0 0]
}
func Modify(sli []int) {
	for i := 0; i < 5; i++ {
		sli = append(sli, i)
	}
	fmt.Println("sli:", sli) // sli: [0 0 0 0 0 0 1 2 3 4]
}

3 - for…range分析

  • range 的本质是一个函数方法,使用时候可以加括号使用
func main() {
	v := [3]int{1, 2, 3}
	for i, value := range (v) { //对形参进行遍历
		v[i] = 3
		// 输出打印遍历值
		fmt.Println("value:", value) // 1 2 3
	}
	// 打印切片的值
	fmt.Println("v", v) // v [3 3 3]
}
  • 修改range得到后的value,不影响原始切片或者数组
type Student struct {
	Name string
	Age  int
}

func main() {
	// 定义一个student 类型切片
	stu1 := Student{"MrWang", 100}
	stu2 := Student{"MrSun", 50}
	stu3 := Student{"MrQiu", 25}
	v := []Student{stu1, stu2, stu3}
	// 循环遍历 数组
	for _, value := range v {
		value.Age = value.Age + 1000 // 对每个人的年龄进行更新
	}
	// 打印切片的值
	fmt.Println(v) // [{MrWang 100} {MrSun 50} {MrQiu 25}]
}
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

无休止符

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值