文章目录
- 1.什么是指针
- 2.容器
- 2.1 数组——固定大小的连续空间
- 2.2 切片(slice)——动态分配大小的连续空间
- 2.2.1 从指定范围中生成切片
- 2.2.2 表示原有的切片
- 2.2.3 重置切片,清空拥有的元素
- 2.2.4 声明切片
- 2.2.5 使用make()函数构造切片
- 2.2.6 使用append()函数为切片添加元素
- 2.2.7 复制切片元素到另一个切片
- 2.2.8 从切片中删除元素
- 3. 映射(map)
- 能够在并发环境中使用的map——sync.Map
- 4. 列表(list)
1.什么是指针
每个变量在运行时都拥有一个地址,这个地址代表变量在内存中的位置。Go语言中使用“&”操作符放在变量前面对变量进行“取地址”操作。
首先来看一下基本语法
1 2 3 4 5 6 | func main() { i := 1 str := "123" var ptr *int = &i fmt.Println(i, ptr, &i, str, &str) } |
输出值在每次运行是不同的,代表cat和str两个变量在运行时的地址。在32位平台上,将是32位地址;64位平台上是64位地址。
每个变量都拥有地址,指针的值就是地址。
再来几个例子:
首先我们得晓得一下:
fmt.Printf的一些参数
取指针内的值:
1 | fmt.Println(*ptr) |
1 2 3 4 5 6 7 8 9 10 | func main() { i := 1 str := "123" ptr := &str//声明指向int的指针 fmt.Println(i, ptr, &i, str, &str) fmt.Println(*ptr) fmt.Printf("%t\n",ptr) fmt.Printf("%T\n",ptr) fmt.Printf("%T\n",*ptr) } |
创建指针的另一种方法——new()函数
new()函数可以创建一个对应类型的指针,创建过程会分配内存。被创建的指针指向的值为默认值。
1 2 3 4 | prtstring := new(string) *prtstring="laji" fmt.Printf("%T",prtstring) fmt.Printf(*prtstring) |
2.容器
2.1 数组——固定大小的连续空间
声明数组
初始化数组
数组可以在声明时使用初始化列表进行元素设置
1 | var array = [3]string{"hhhh", "oooo", "kkkk"} |
也可以使用,“…”表示让编译器确定数组大小。
1 | var array1 = [...]string{"111"} |
数组遍历:
1 2 3 | for k, v := range array{ fmt.Println(k, v) } |
Go的数组是值类型,数组间不会互相影响
1 2 3 4 5 6 7 8 | fmt.Println(&array[0]) test(array) ---------------------- func test(ints [3]string) { fmt.Println(&ints[0]) } |
地址不同了
2.2 切片(slice)——动态分配大小的连续空间
切片是引用类型
切片默认指向一段连续内存区域,可以是数组,也可以是切片本身。
从连续内存区域生成切片是常见的操作,语法如下:
slice [开始位置:结束位置]
1 2 3 | ● slice表示目标切片对象。 ● 开始位置对应目标切片对象的索引。 ● 结束位置对应目标切片的结束索引。 |
从数组或切片生成新的切片拥有如下特性:
● 取出的元素数量为:结束位置-开始位置。
● 取出元素不包含结束位置对应的索引,切片最后一个元素使用slice[len(slice)]获取。
● 当缺省开始位置时,表示从连续区域开头到结束位置。
● 当缺省结束位置时,表示从开始位置到整个连续区域末尾。
● 两者同时缺省时,与切片本身等效。
● 两者同时为0时,等效于空切片,一般用于切片复位。
● 根据索引位置取切片slice元素值时,取值范围是(0~len(slice)-1),超界会报运行时错误。生成切片时,结束位置可以填写len(slice)但不会报错。
2.2.1 从指定范围中生成切片
切片和数组密不可分。
如果将数组理解为一栋办公楼,那么切片就是把不同的连续楼层出租给使用者。出租的过程需要选择开始楼层和结束楼层,这个过程就会生成切片。
含义就是:
1 2 3 4 | var slice = [3]int{1, 2, 3} ints := slice[0:2] // 1 2 ints[0]=2 // 修改 1 为2 fmt.Println(slice) //查看原数组是否被修改 |
2.2.2 表示原有的切片
slice[:] 表示得到和原数组大小一致的切片
2.2.3 重置切片,清空拥有的元素
slice[0:0] 切片大小变成空
1 2 | i := slice[0:0] fmt.Println(i) |
结果为:
1 | [] |
2.2.4 声明切片
每一种类型都可以拥有其切片类型,表示多个类型元素的连续集合。因此切片类型也可以被声明。
1 | var name []int |
2.2.5 使用make()函数构造切片
1 2 3 4 | var name []int name = make([]int, 3, 5) i2 := make([]int, 2, 8) fmt.Println(name,len(name),i2,len(i2)) |
i2均是预分配2个元素的切片,只是i2的内部存储空间已经分配了8个,但实际使用了2个元素。
2.2.6 使用append()函数为切片添加元素
Go语言的内建函数append()可以为切片动态添加元素。每个切片会指向一片内存空间,这片空间能容纳一定数量的元素。当空间不能容纳足够多的元素时,切片就会进行“扩容”。“扩容”操作往往发生在append()函数调用时。
1 2 3 4 5 | var name []int name= append(name, 1) fmt.Println(name,len(name),cap(name)) name= append(name, 2) fmt.Println(name,len(name), cap(name)) |
切片在扩容时,容量的扩展规律按容量的2倍数扩充,例如1、2、4、8、16……
1 2 3 4 5 | var nums []int for i:=0;i<10;i++{ nums= append(nums, i) fmt.Printf("len:%d,cap:%d,pointer:%p\n",len(nums),cap(nums),nums) } |
2.2.7 复制切片元素到另一个切片
使用Go语言内建的copy()函数,可以迅速地将一个切片的数据复制到另外一个切片空间中,copy()函数的使用格式如下
1 2 3 4 5 6 7 8 9 10 11 12 | src := make([]int, 4, 8) fmt.Printf("len:%d,cap:%d,pointer:%p\n,srcvalue:%v\n", len(src), cap(src), src, src) dest := make([]int, 2, 10) fmt.Printf("len:%d,cap:%d,pointer:%p\n,destvalue:%v\n", len(dest), cap(dest), dest, dest) src[0] = 1 fmt.Printf("len:%d,cap:%d,pointer:%p\n,destvalue:%v\n", len(dest), cap(dest), dest, dest) src[3] = 5 copy(dest, src) fmt.Printf("len:%d,cap:%d,pointer:%p,destvalue:%v\n", len(dest), cap(dest), dest, dest) dest[0]=1213 fmt.Printf("len:%d,cap:%d,pointer:%p,destvalue:%v\n", len(dest), cap(dest), dest, dest) fmt.Printf("len:%d,cap:%d,pointer:%p\n,srcvalue:%v\n", len(src), cap(src), src, src) |
2.2.8 从切片中删除元素
Go语言并没有对删除切片元素提供专用的语法或者接口,需要使用切片本身的特性来删除元素。
1 | customer = append(customer[:index], customer[index+1:]...) |
删除过程。
连续容器的元素删除无论是在任何语言中,都要将删除点前后的元素移动到新的位置。随着元素的增加,这个过程将会变得极为耗时。因此,当业务需要大量、频繁地从一个切片中删除元素时,如果对性能要求较高,就需要反思是否需要更换其他的容器(如双链表等能快速从删除点删除元素)。
3. 映射(map)
Go语言提供的映射关系容器为map。map使用散列表(hash)实现。
1 2 3 4 | mmap := make(map[string]int) mmap["okok"]=16 fmt.Println(mmap["okok"]) fmt.Println(mmap["ok2ok"]) |
填充式创建:
遍历map的“键值对”——访问每一个map中的关联关系
1 2 3 4 5 6 7 8 9 | for k, v := range mmap { fmt.Println(k, v) } for _, v := range mmap { fmt.Println( v) } for k:= range mmap { fmt.Println(k) } |
使用delete()函数从map中删除键值对
清空map中的所有元素
Go语言中并没有为map提供任何清空所有元素的函数、方法。清空map的唯一办法就是重新make一个新的map。不用担心垃圾回收的效率,Go语言中的并行垃圾回收效率比写一个清空函数高效多了。
能够在并发环境中使用的map——sync.Map
sync.Map有以下特性:
● 无须初始化,直接声明即可。
● sync.Map不能使用map的方式进行取值和设置等操作,而是使用sync.Map的方法进行调用。Store表示存储,Load表示获取,Delete表示删除。
● 使用Range配合一个回调函数进行遍历操作,通过回调函数返回内部遍历出来的值。Range参数中的回调函数的返回值功能是:需要继续迭代遍历时,返回true;终止迭代遍历时,返回false。
4. 列表(list)
列表是一种非连续存储的容器,由多个节点组成,节点通过一些变量记录彼此之间的关系。列表有多种实现方法,如单链表、双链表等。
初始化列表
1.通过container/list包的New方法初始化list
1 | l := list.New() |
2.通过声明初始化list
1 | l2 := list.List{} |
双链表支持从队列前方或后方插入元素,分别对应的方法是Push Front和Push Back。
举例:
1 2 3 4 5 | l := list.New() l.PushBack("fiest") //增加尾部 front := l.PushFront("dddd") // 增加头部 l.InsertAfter("aaaa", front) l.Remove(front) |
遍历列表——访问列表的每一个元素