飞道的博客

Golang入门 - 指针&切片(容器)

377人阅读  评论(0)

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
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场