golang随记 | 实习笔记

1.defer的注意事项和细节

  • 当go执行到一个defer时,不会立即执行defer后的语句,而是将defer后的语句压入到一个独立栈中【暂时称该栈为defer栈】,然后继续执行函数下一个语句。
  • 当函数执行完毕后,再从defer栈中,依次从栈顶取出语句执行(注:遵守栈 先入后出的机制出栈,然后执行),所以前面看到案例的输出顺序。
  • 在defer 将语句放入到栈时,也会将相关的值拷贝同时入栈。

例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
func accumulate(counterPtr *int) {
for i := 0; i < 5; i++ {
*counterPtr++
defer fmt.Println(*counterPtr)
}
fmt.Printf("counter = %d \n", *counterPtr)
}

func main() {
var couter = 0
accumulate(&couter)
}

输出结果:

1
2
3
4
5
6
counter = 5
5
4
3
2
1

2.GoLang中&与*的区别以及使用

&符号的意思是对变量取地址
*符号的意思是对指针取值

例子

1
2
3
4
5
6
7
8
9
10
11
func main() {
var a *int // 存储的是int的指针,目前为空
var b int = 4 // 存储的是int的值
a = &b // a 指向 b 的地址
a = b // a 无法等于 b,会报错,a是指针,b是值,存储的类型不同
fmt.Println(a) // a:0xc00000a090(返回了地址)
fmt.Println(*a) // *a:4(返回了值)
fmt.Println(*&a) // *抵消了&,返回了0xc00000a090本身
*a = 5 // 改变 a 的地址的值
fmt.Println(b) // b:5,改变后 b 同样受到改变,因为 a 的地址是指向 b 的
}

GO的结构体和数组以及string均是值类型 ,切片是引用类型

值类型和引用类型
值类型:int、float、bool、string、数组array、结构体struct

引用类型:指针、切片slice、map、接口interface、函数func、管道chan

区别
值类型:

变量直接存储值,内存通常在栈中分配。
给新的变量赋值时(拷贝时),为深拷贝,直接开辟新的内存地址存储值。

引用类型:

变量直接存储内存地址,这个地址存储值。内存通常在堆上分配。
给新的变量赋值时(拷贝时),为浅拷贝,新的变量通过指针指向原来的内存地址。可以使用copy关键字实现引用类型的深拷贝。
当如果没有任何一个变量引用这个地址时,这个地址就会被GC垃圾回收。

Go语言中函数的参数永远是拷贝的

1
2
3
4
5
6
func(接收者变量  *接收者类型) 函数名称 (参数)(返回值){}  
// 这里的前缀代表该方法的接收者,只有该类型的变量可以调用该方法
// 接收者代表的是调用该方法的具体类型变量,多用类型名首字母小写表示
// 类似于Java语言里面的对象继承的多态属性,不同类型对象调用的方法实现不同

//接收者变量的类型可以是任何类型,不仅仅是结构体,任何类型都可以拥有子方法

Go结构体嵌套可以模拟实现继承

Go for循环里面使用协程需要复制一份再进行操作,否则会出现读取数据异常
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package main

import (
"fmt"
"time"
)

type user struct {
name string
}

func main() {
var users []*user
users = append(users, &user{name: "john"})
users = append(users, &user{name: "jane"})
users = append(users, &user{name: "joe"})
for _, user := range users { // 此处的user是指针,每次循环所在地址不变,只是地址所在的数据值发生了变化
fmt.Printf("%p\n", &user)
user := user //协程里面需要循环的变量需要复制一份,不然会出现协程里面读取数据错误
fmt.Printf("%p\n", &user)
go func() {
fmt.Printf("%p\n", user)
fmt.Println(user.name)
}()
}
time.Sleep(2 * time.Second)
}

golang随记 | 实习笔记
https://zty-f.github.io/2022/06/22/golang随记/
作者
ZTY
发布于
2022年6月22日
更新于
2025年1月2日
许可协议