指针
指针就是地址。指针变量就是存储地址的变量
指针使用
&p : 引用
*p : 解引用、间接引用
栈帧
用来给函数运行提供内存空间。取内存于 stack 上。
当函数调用时,产生栈帧。函数调用结束,释放栈帧。
- 栈帧存储:
- 局部变量
- 形参 (形参与局部变量存储地位等同)
- 内存字段描述值
指针使用注意
空指针:未被初始化的指针。
var p *int
fmt.Println(*p) --> err
格式化输出
%q
:以 Go 语言格式显示字符串。默认带有 "" 符
%v
:显示对应数据详细信息
变量存储
func swap(x, y *int) {
*x, *y = *y, *x
}
等号左边的变量:代表变量所指向的内存空间。(写)
等号右边的变量:代表变量内存空间存储的数据值。(读)
指针的函数传参(传引用)
传地址(引用):将形参的地址值作为函数参数传递。
传值(数据):将实参的值拷贝一份给形参
传引用:在 A 栈帧内部,修改 B 栈帧中的变量值
切片
为什么用切片
- 数组的容量固定,不能自动拓展。
- 值传递。数组作为函数参数时,将整个数组值拷贝一份给形参。
在 Go 语言中,几乎可以在所有的场景中,使用切片替换数组使用。
切片的本质:
不是一个数组的指针,是一种数据结构体,用来操作数组内部元素。
// runtime/slice.go
type slice struct {
*p
len
cap
}
切片的使用
-
数组和切片定义区别:
- 创建数组时
[]
指定数组长度 - 创建切片时,
[]
为空,或者...
- 创建数组时
-
切片名称[low:high:max]
- low:启示下标位置
- high:结束下表位置
- 长度 len:high - low
- 容量 cap:max-low
-
截取数组,初始化切片时,没有指定切片容量时,切片容量跟随原数组(切片)
-
s[:high:max]
:从 0 开始,到 high 结束。(不包含 high) -
s[low:]
:从 low 开始,到末尾 -
s[:high]
:从 0 开始,到 high 结束。容量跟随原先容量。【常用】
-
-
切片创建:
- 自动推导类型创建切片。
slice := []int{1, 2, 3}
slice := make([]int, 长度, 容量)
-
slice := make([]int, 长度)
创建切片时,没有指定容量,容量==长度
- 自动推导类型创建切片。
切片做函数参数 --- 传引用(传地址)
-
append:再切片末尾追加元素
append(切片对象, 待追加元素)
- 向切片增加元素时,切片的容量会自动增加。1024 以下时,一两倍方式增加
-
copy 复制切片
copy(目标位置切片s1,源切片s2)
- 拷贝过程中,直接对应位置拷贝
- 不同类型的切片无法复制
- 如果s1的长度大于s2的长度,将s2中对应位置上的值替换s1中对应位置的值。如果s1的长度小于s2的长度,多余的将不做替换
map
字典、映射,key-value, key:唯一、无需。不能是引用类型数据。
-
创建方式:
-
var m map[int]string
---不能存储数据 -
m := map[int]string{}
---能存储数据 -
m := make(map[int]string)
---默认 len = 0 m := make(map[int]string, 10)
-
-
初始化:
-
var m map[int]string = map[int]string{1: "aaa", 2: "bbb"}
保证 key 彼此不重复 m := map[int]string{1: "aaa", 2: "bbb"}
-
-
赋值:
- 赋值过程中,如果新 map 元素的 key 与原 map 元素 key 相同 ---> 覆盖(替换)
- 赋值过程中,如果新 map 元素的 key 与原 map 元素 key 不同 ---> 添加
-
map 的使用
- 遍历 map
for key, value := range map { }
- 判断 map 中 key 是否存在
- map[下标] 运算:返回两个值,第一个表示 value 的值,如果 value 不存在,则为 nil。第二个表示 key 是否存在的 bool 类型,存在为 true,不存在为 false
val, has := map[1]
-
删除 map
-
delete()
函数:- 参数1:待删除元素的 map
- 参数2:key 值
-
delete(map, key)
- 删除一个不存在的 key,不会报错
- map 做函数参数和返回值,传引用
-
结构体
结构体是一种数据类型。类型定义,地位等价于 int、byte、bool、string…,通常放在全局位置。
type Person struct {
name string
sex byte
age int
}
普通变量定义和初始化
- 顺序初始化:依次将结构体内部所有成员初始化
var man Person = Person{"andy", 'm', 20}
- 指定成员初始化:未初始化的成员变量,取该数据类型对应的默认值
man := Person{name: "andy", age: 20}
普通变量的赋值和使用
- 使用
.
索引成员变量var man Person man.name = "nike" man.sex = 'm' man.age = 99
结构体变量的比较
- 比较:只能使用
==
和!=
,不能使用> < >= <= …
- 相同结构体类型(成员变量的类型、个数、顺序一致),变量之间可以直接赋值
结构体地址
结构体变量的地址 == 结构体首个元素的地址
结构体传参
将结构体变量的值拷贝一份传递。 ---几乎不用。内存消耗大,效率低。
unSafe.Sizeof(变量名)
---查看此种类型的变量所占用的内存空间大小
指针变量定义和初始化
-
顺序初始化:依次将结构体内部所有成员初始化
var man *Person = &Person{"andy", 'm', 20}
new(Person)
p := new(Person)
p.name = "name"
p.age = 10
指针索引成员变量
- 使用
.
索引成员变量var man Person man.name = "nike" man.sex = 'm' man.age = 99
结构体地址
结构体指针变量的值 == 结构体首个元素的地址
结构体指针传参
将结构体变啊零地址值传递(传引用)。---使用频率非常高
unSafe.Sizeof(指针)
:不管何种类型的指针,在 64位操作系统下,大小一致,均为 8 byte
结构体指针作函数返回值
可以返回局部变量的值
不能返回局部变量的地址 --- 局部变量保存在栈帧上,函数调用结束后,栈帧释放,局部变量的地址,不再受系统保护,随时可能分配给其他程序。
字符串处理函数
-
字符串按指定分隔符拆分:
Split
:ret := strings.Split(str, "-")
-
字符串按空格拆分:Fields
ret = strings.Fields(str)
-
判断字符串结束标记:
HasSuffix
flg := strings.HasSuffix("test.txt", ".aaa")
-
判断字符串起始标识:
HasPrefix
flg := strings.HasPrefix("test.txt", "te.")