【声明】
非完全原创,部分内容来自于学习其他人的理论和B站视频。如果有侵权,请联系我,可以立即删除掉。
0、Go数据类型分类
引用类型包括:指针,slice,map,channel,接口,函数类型等,其本质是一个指向对象的指针
值类型有:数组、结构体、基本数据类型
一、指针
指针是一个代表着某个内存地址的值。这个内存地址往往是在内存中存储的另一个变量的值的起始位置
1、特点
(1)默认值 nil
,没有 NULL
和null
常量
(2)操作符 &
取变量地址,*
通过指针访问目标对象
(3)不支持指针运算,不支持 “->” 运算符,直接⽤ .
访问目标成员
2、基本使用
n := 66
var p *int = nil //声明一个变量p, 类型为 *int
p = &n
*p = 888
fmt.Printf("n = %d, &n = 0x%x, *p = %d, p = 0x%x\n", n, &n, *p, p)
var p1 *int //声明方式1
p1 = new(int) //p1指向匿名的int变量
p2 := new(int) //声明方式2
*p2 = 111
output:
n = 888, &n = 0xc0000aa0c0, *p = 888, p = 0xc0000aa0c0
3、指针作为参数传递
func swap(x, y *int) {
*x, *y = *y, *x
}
func main() {
a := 6666
b := 8888
swap02(&a, &b) //变量值交换
fmt.Printf("a = %d, b = %d\n", a, b)
二、数组
1、概念
数组是存储同一种数据类型多个元素的集合。它既可以存储基本数据类型,也可以存储引用数据类型。数组每个数据被称为数组元素,其包含的元素个数被称为数组的长度。
2、数组定义、遍历
声明明语法如下:
var 数组变量名 [数组长度]Type
注意:数组长度
不能是变量
var n int = 6
var a [n]int //err, non-constant array bound n
var b [10]int //方式1
c := [10]int{
} //方式2:10个元素均为0
d := [...]int{
1, 2, 3} //方式3:数组长度为3
e := [...]int{
2: 6, 4: 8} //方式4:数组长度为5
//二位数组
f := [...][2]int{
{
0, 1}, {
2, 3}, {
4, 5}} //方式1:第2维不能用...
g := [7][2]int{
1: {
0: 0}, 5: {
1: 1}} //方式2
h := [2][2]int{
{
0, 0}}
for i := 0; i < len[d]; i++ {
fmt.Printf("d[%d] = %d\n", i, d[i])
}
//range具有两个返回值,第一个返回值是元素的数组下标,第二个返回值是元素的值
for i, v := range e {
fmt.Println("e[", i, "]=", v)
}
数组的特点是:
(1)长度是固定的,因此定义时长度不能为变量,且数组定义后其长度不可修改
(2)数组是随机访问的,因为其地址是连续的,可以直接通过索引来计算访问的地址,时间为O(1)
func main(){
a := [3][3]int8{
}
for i, val := range a {
for j := 0; j < len(val); j++ {
fmt.Printf("0x%x\t", &a[i][j])
}
fmt.Println()
}
}
output:
0xc0000140b0 0xc0000140b1 0xc0000140b2
0xc0000140b3 0xc0000140b4 0xc0000140b5
0xc0000140b6 0xc0000140b7 0xc0000140b8
3、数组作为参数
go语言中,数组作为函数的参数时,默认以值的方式传递的,因此开销会比较大。
数组指针作为参数时,则是地址传递
func val_func(array [3]int) {
array[0] = 6 // 值传递,此处修改不影响原数组
}
func addr_func(array *[3]int) {
(*array)[0] = 6 //引用传递,此处修改会影响原数组
}
func main() {
arr := [3]int{
1, 2, 3}
val_func(arr)
fmt.Println(arr)
addr_func(&arr)
fmt.Println(arr)
}
output:
[1 2 3]
[6 2 3]
三、切片slice
由于数组的长度是确定的,且数组在定义后其长度无法再次修改,因此在遇到不确定长度的场景时,需要用到切片slice
切片并不是数组或数组指针,它通过内部指针和相关属性引⽤数组⽚段,以实现变⻓⽅案。它是一个引用类型
1、切片的声明
var s1 []int //和数组声明差不多,只是不需要指定长度
//make([]T, length, capacity) //capacity省略,则和length的值相同
var s2 []int = make([]int, 1, 2)
s3 := make([]int, 0, 0)
s4 := []int{
1, 2} //创建切片并初始化
2、切片的操作
操作 | 含义 |
---|---|
s[n] | 切片s中索引位置为n的项 |
s[:] | 从切片s的索引位置0到len(s)-1处所获得的切片 |
s[low:] | 从切片s的索引位置low到len(s)-1处所获得的切片 |
s[:high] | 从切片s的索引位置0到high处所获得的切片,len=high |
s[low:high] | 从切片s的索引位置low到high处所获得的切片,len=high-low |
s[low:high:max] | 从切片s的索引位置low到high处所获得的切片,len=high-low,cap=max-low |
len(s) | 切片s的长度,总是<=cap(s) |
cap(s) | 切片s的容量,总是>=len(s) |
var s1 []int
//追加元素
s1 = append(s1, 1, 2) //追加2个元素
fmt.Printf("s2 len = %d, cap = %d\n", len(s2), cap(s2))
//复制元素:部分覆盖
data := [...]int{
0, 1, 2, 3, 4, 5}
s2 := data[3