1.什么是指针
每个变量在运行时都拥有一个地址,这个地址代表变量在内存中的位置。Go语言中使用“&”操作符放在变量前面对变量进行“取地址”操作。
首先来看一下基本语法
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的一些参数
取指针内的值:
fmt.Println(*ptr)
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()函数可以创建一个对应类型的指针,创建过程会分配内存。被创建的指针指向的值为默认值。
prtstring := new(string)
*prtstring="laji"
fmt.Printf("%T",prtstring)
fmt.Printf(*prtstring)
2.容器
2.1 数组——固定大小的连续空间
声明数组
初始化数组
数组可以在声明时使用初始化列表进行元素设置
var array = [3]string{"hhhh", "oooo", "kkkk"}
也可以使用,“…”表示让编译器确定数组大小。
var array1 = [...]string{"111"}
数组遍历:
for k, v := range array{
fmt.Println(k, v)
}
Go的数组是值类型,数组间不会互相影响
fmt.Println(&array[0])
test(array)
----------------------
func test(ints [3]string) {
fmt.Println(&ints[0])
}
地址不同了
2.2 切片(slice)——动态分配大小的连续空间
切片是引用类型
切片默认指向一段连续内存区域,可以是数组,也可以是切片本身。
从连续内存区域生成切片是常见的操作,语法如下:
slice [开始位置:结束位置]
● slice表示目标切片对象。
● 开始位置对应目标切片对象的索引。
● 结束位置对应目标切片的结束索引。
从数组或切片生成新的切片拥有如下特性:
● 取出的元素数量为:结束位置-开始位置。
● 取出元素不包含结束位置对应的索引,切片最后一个元素使用slice[len(slice)]获取。
● 当缺省开始位置时,表示从连续区域开头到结束位置。
● 当缺省结束位置时,表示从开始位置到整个连续区域末尾。
● 两者同时缺省时,与切片本身等效。
● 两者同时为0时,等效于空切片,一般用于切片复位。
● 根据索引位置取切片slice元素值时,取值范围是(0~len(slice)-1),超界会报运行时错误。生成切片时,结束位置可以填写len(slice)但不会报错。
2.2.1 从指定范围中生成切片
切片和数组密不可分。
如果将数组理解为一栋办公楼,那么切片就是把不同的连续楼层出租给使用者。出租的过程需要选择开始楼层和结束楼层,这个过程就会生成切片。
含义就是:
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] 切片大小变成空
i := slice[0:0]
fmt.Println(i)
结果为:
[]
2.2.4 声明切片
每一种类型都可以拥有其切片类型,表示多个类型元素的连续集合。因此切片类型也可以被声明。
var name []int
2.2.5 使用make()函数构造切片
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()函数调用时。
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……
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()函数的使用格式如下
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语言并没有对删除切片元素提供专用的语法或者接口,需要使用切片本身的特性来删除元素。
customer = append(customer[:index], customer[index+1:]...)
删除过程。
连续容器的元素删除无论是在任何语言中,都要将删除点前后的元素移动到新的位置。随着元素的增加,这个过程将会变得极为耗时。因此,当业务需要大量、频繁地从一个切片中删除元素时,如果对性能要求较高,就需要反思是否需要更换其他的容器(如双链表等能快速从删除点删除元素)。
3. 映射(map)
Go语言提供的映射关系容器为map。map使用散列表(hash)实现。
mmap := make(map[string]int)
mmap["okok"]=16
fmt.Println(mmap["okok"])
fmt.Println(mmap["ok2ok"])
填充式创建:
遍历map的“键值对”——访问每一个map中的关联关系
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
l := list.New()
2.通过声明初始化list
l2 := list.List{}
双链表支持从队列前方或后方插入元素,分别对应的方法是Push Front和Push Back。
举例:
l := list.New()
l.PushBack("fiest") //增加尾部
front := l.PushFront("dddd") // 增加头部
l.InsertAfter("aaaa", front)
l.Remove(front)
遍历列表——访问列表的每一个元素
转载:https://blog.csdn.net/littlewhitevg/article/details/106503334