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

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)

在这里插入图片描述

下面列举append的一些操作:

  1. 将切片 b 的元素追加到切片 a 之后:a = append(a, b…)

  2. 复制切片 a 的元素到新的切片 b 上:
    b = make([]T, len(a))
    copy(b, a)

  3. 删除位于索引 i 的元素:a = append(a[:i], a[i+1:]…)

  4. 切除切片 a 中从索引 i 至 j 位置的元素:a = append(a[:i], a[j:]…)

  5. 为切片 a 扩展 j 个元素长度:a = append(a, make([]T, j)…)

  6. 在索引 i 的位置插入元素 x:a = append(a[:i], append([]T{x}, a[i:]…)…)

  7. 在索引 i 的位置插入长度为 j 的新切片:a = append(a[:i], append(make([]T, j), a[i:]…)…)

  8. 在索引 i 的位置插入切片 b 的所有元素:a = append(a[:i], append(b, a[i:]…)…)

  9. 取出位于切片 a 最末尾的元素 x:x, a = a[len(a)-1], a[:len(a)-1]

  10. 将元素 x 追加到切片 a:a = append(a, x)

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)

在这里插入图片描述

遍历列表——访问列表的每一个元素
在这里插入图片描述

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
个人学习golang笔记,从各种教程中总结而来,作为入门参考。目录如下 目录 1. 入门 1 1.1. Hello world 1 1.2. 命令行参数 2 2. 程序结构 3 2.1. 类型 4 2.1.1. 命名类型(named type)与未命名类型(unamed type) 4 2.1.2. 基础类型(underlying type) 4 2.1.3. 可赋值性 5 2.1.4. 类型方法集 6 2.1.5. 类型声明 6 2.2. 变量 8 2.2.1. 变量声明 8 2.2.2. 类型零值 12 2.2.3. 指针 13 2.3. 赋值 17 2.4. 包和文件 17 2.5. 作用域 18 2.6. 语句 19 2.7. 比较运算符 20 2.8. 类型转换 21 2.9. 控制流 23 2.9.1. If 23 2.9.2. Goto 24 2.9.3. For 25 2.9.4. Switch 25 2.9.5. break语句 31 2.9.6. Continue语句 31 3. 基础数据类型 31 3.1. golang类型 31 3.2. Numeric types 32 3.3. 字符串 33 3.3.1. 什么是字符串 33 3.3.2. 字符串底层概念 35 3.3.3. 获取每个字节 38 3.3.4. Rune 39 3.3.5. 字符串的 for range 循环 40 3.3.6. 用字节切片构造字符串 41 3.3.7. 用rune切片构造字符串 42 3.3.8. 字符串的长度 42 3.3.9. 字符串是不可变的 42 3.3.10. UTF8(go圣经) 43 3.4. 常量 45 3.4.1. 常量定义 45 3.4.2. 常量类型 46 3.4.3. Iota 46 4. 组合数据类型 47 4.1. 数组 47 4.1.1. 数组概述 47 4.1.2. 数组的声明 49 4.1.3. 数组的长度 50 4.1.4. 遍历数组 50 4.1.5. 多维数组 51 4.2. 切片 52 4.2.1. 什么是切片 52 4.2.2. 切片概述 55 4.2.3. 创建一个切片 55 4.2.4. 切片遍历 57 4.2.5. 切片的修改 58 4.2.6. 切片的长度和容量 60 4.2.7. 追加切片元素 62 4.2.8. 切片的函数传递 65 4.2.9. 多维切片 66 4.2.10. 内存优化 67 4.2.11. nil slice和empty slice 69 4.2.12. For range 70 4.3. 结构 71 4.3.1. 什么是结构体? 71 4.3.2. 结构体声明 73 4.3.3. 结构体初始化 77 4.3.4. 嵌套结构体(Nested Structs) 81 4.3.5. 匿名字段 82 4.3.6. 导出结构体和字段 84 4.3.7. 结构体相等性(Structs Equality) 85 4.4. 指针类型 86 4.5. 函数 87 4.6. map 87 4.6.1. 什么是map 87 4.6.2. 声明、初始化和make 89 4.6.3. 给 map 添加元素 91 4.6.4. 获取 map 中的元素 91 4.6.5. 删除 map 中的元素 92 4.6.6. 获取 map 的长度 92 4.6.7. Map 的相等性 92 4.6.8. map的排序 92 4.7. 接口 93 4.7.1. 什么是接口? 93 4.7.2. 接口的声明与实现 96 4.7.3. 接口的实际用途 97 4.7.4. 接口的内部表示 99 4.7.5. 空接口 102 4.7.6. 类型断言 105 4.7.7. 类型选择(Type Switch) 109 4.7.8. 实现接口:指针接受者与值接受者 112 4.7.9. 实现多个接口 114 4.7.10. 接口的嵌套 116 4.7.11. 接口的零值 119 4.8. Channel 120 4.9. 类型转换 120 5. 函数 120 5.1. 函数的声明 121 5.2. 一个递归函数的例子( recursive functions) 121 5.3. 多返回值 121 5.4. 命名返回值 121 5.5. 可变函数参数 122 5.6. Defer 123 5.6.1. Defer语句介绍 123 5.6.2. Defer使用场景 128 5.7. 什么是头等(第一类)函数? 130 5.8. 匿名函数 130 5.9. 用户自定义的函数类型 132 5.10. 高阶函数(装饰器?) 133 5.10.1. 把函数作为参数,传递给其它函数 134 5.10.2. 在其它函数中返回函数 134 5.11. 闭包 135 5.12. 头等函数的实际用途 137 6. 微服务创建 140 6.1. 使用net/http创建简单的web server 140 6.2. 读写JSON 144 6.2.1. Marshal go结构到JSON 144 6.2.2. Unmarshalling JSON 到Go结构 146 7. 方法 146 7.1. 什么是方法? 146 7.2. 方法示例 146 7.3. 函数和方法区别 148 7.4. 指针接收器与值接收器 153 7.5. 那么什么时候使用指针接收器,什么时候使用值接收器? 155 7.6. 匿名字段的方法 156 7.7. 在方法中使用值接收器 与 在函数中使用值参数 157 7.8. 在方法中使用指针接收器 与 在函数中使用指针参数 159 7.9. 在非结构体上的方法 161 8. 并发入门 162 8.1. 并发是什么? 162 8.2. 并行是什么? 162 8.3. 从技术上看并发和并行 163 8.4. Go 对并发的支持 164 9. Go 协程 164 9.1. Go 协程是什么? 164 9.2. Go 协程相比于线程的优势 164 9.3. 如何启动一个 Go 协程? 165 9.4. 启动多个 Go 协程 167 10. 信道channel 169 10.1. 什么是信道? 169 10.2. 信道的声明 169 10.3. 通过信道进行发送和接收 169 10.4. 发送与接收默认是阻塞的 170 10.5. 信道的代码示例 170 10.6. 信道的另一个示例 173 10.7. 死锁 174 10.8. 单向信道 175 10.9. 关闭信道和使用 for range 遍历信道 176 11. 缓冲信道和工作池(Buffered Channels and Worker Pools) 179 11.1. 什么是缓冲信道? 179 11.2. 死锁 182 11.3. 长度 vs 容量 183 11.4. WaitGroup 184 11.5. 工作池的实现 186 12. Select 188 12.1. 什么是 select? 188 12.2. 示例 189 12.3. select 的应用 190 12.4. 默认情况 190 12.5. 死锁与默认情况 191 12.6. 随机选取 191 12.7. 这下我懂了:空 select 191 13. 文件读写 191 13.1. GoLang几种读文件方式的比较 197 14. 个人 197 14.1. ++,-- 198 14.2. 逗号 198 14.3. 未使用的变量 199 14.4. Effective go 199 14.4.1. 指针 vs. 值 199 14.5. 可寻址性-map和slice的区别 201 14.5.1. slice 201 14.5.2. map 202 14.6. golang库 203 14.6.1. unicode/utf8包 203 14.6.2. time包 205 14.6.3. Strings包 205 14.6.4. 输入输出 212 14.6.5. 正则处理 224 14.6.6. Golang内建函数 226

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值