Go内建容器——Golang学习笔记3
文章目录
- 数组
- 切片(Slice)
- 键值对(Map)
- 字符和字符串处理
- strings包中的各种操作方法;
- Fields,Split,Join
- Contains,Index
- ToLower, ToUpper
- Trim,TrimRight,TrimLeft
数组
- 数组的空间大小写在类型前;
- 除常规遍历数组方法之外,还可以通过range关键字进行遍历;
- 可通过 _ 省略变量,不仅仅在range中,任何地方都可以通过 _ 省略变量;
- 数组是值类型,调用 func f(arr [10] int)会拷贝数组;
- 数组是作为函数参数时是值类型,即拷贝;其他语言中获取数组名即获取数组的首元素地址,是引用传递;
- [10] int 和[20] int是不同的数据类型;
- Go中一般不直接使用数组。
- 数组定义
- 数组定义的案例
var arr1 [5]int // 这里仅仅定义为对数组初始化,但go给数组每个元素赋值默认值0arr2 := [3]int{1, 3, 5} // 使用:=定义时必须进行初始化arr3 := [...]int{2, 4, 6, 8, 10} // 数组欺骗var grid [4][5]bool // 多维数组fmt.Println(arr1, arr2, arr3)
fmt.Println(grid)
输出结果:
[0 0 0 0 0] [1 3 5] [2 4 6 8 10]
[[false false false false false] [false false false false false] [false false false false false] [false false false false false]]
- 数组遍历
- 数组遍历的案例
// 遍历方法一 使用range关键字
for i := range arr3 { // 关键字range获得数组arr3的下标fmt.Println(arr3[i])
}
//关于range另外写法
for i, v := range arr3 {// 关键字range同时获得数组arr3的下标和对应的元素值// 若不想写变量i,可以用_替代ifmt.Println(i, v) // 输出下标以及元素值
}// 遍历方法二
for i := 0; i < len(arr2); i++ {fmt.Println(arr2[i])
}
- 数组参数传递
数组参数传递的案例
// 值传递
func printArray1(arr [5]int){arr[0] = 100 // 验证数组是值传递而非引用传递for i, v := range arr {fmt.Println(i, v)}
}// 引用传递,借用指针
func printArray2(arr *[5]int){arr[0] = 100 // 验证数组是值传递而非引用传递for i, v := range arr {fmt.Println(i, v)}
}func main() {var arr1 [5]int // 这里仅仅定义为对数组初始化,但go给数组每个元素赋值默认值0arr2 := [3]int{1, 3, 5} // 使用:=定义时必须进行初始化arr3 := [...]int{2, 4, 6, 8, 10}fmt.Println("--------------值传递")fmt.Println("printArray1(arr1)")printArray1(arr1) // 可行fmt.Println("printArray1(arr3)")printArray1(arr3) // 可行// printArray1(arr2) // 不可行fmt.Println("arr1 and arr3")fmt.Println(arr1, arr3)fmt.Println("-------------引用传递")fmt.Println("printArray2(&arr1)")printArray2(&arr1) // 取地址fmt.Println("printArray2(&arr3)")printArray2(&arr3)fmt.Println("arr1 and arr3")fmt.Println(arr1, arr3) // 数组的第一个元素被改为100
}
输出结果:
--------------值传递
printArray_value(arr1)
0 100
1 0
2 0
3 0
4 0
printArray_value(arr3)
0 100
1 4
2 6
3 8
4 10
arr1 and arr3
[0 0 0 0 0] [2 4 6 8 10] // 第一个元素没有变成100
-------------引用传递
printArray_reference(&arr1)
0 100
1 0
2 0
3 0
4 0
printArray_reference(&arr3)
0 100
1 4
2 6
3 8
4 10
arr1 and arr3
[100 0 0 0 0] [100 4 6 8 10] // 第一个元素变成100
注
为什么要使用range
- 意义明确,美观
- c++:没有类似能力
- Java/Python:只能for each value,不能同时获取i, v
切片(Slice)
- 切片的定义
slice本身没有数据,是对底层array的一个view;
slice是引用类型,是数组array的引用,是动态数组;
切片的定义的案例
func main() {arr := [...]int{0, 1, 2, 3, 4, 5, 6, 7, 8}fmt.Println("arr[2:6] = ", arr[2:6]) // slice是引用类型,是数组的引用,是动态数组fmt.Println("arr[:6] = ", arr[:6])fmt.Println("arr[2:] = ", arr[2:])fmt.Println("arr[:] = ", arr[:]) // arr[:] 和 arr不同;arr[:]是切片,动态数组,而arr仅仅是数组
}
输出结果:
arr[2:6] = [2 3 4 5]
arr[:6] = [0 1 2 3 4 5]
arr[2:] = [2 3 4 5 6 7 8]
arr[:] = [0 1 2 3 4 5 6 7 8]
- 切片的引用传递
- 切片的引用传递的案例
func updateSlice(s []int) { // 不带长度的,表示Slices[0] = 100
}func main() {arr := [...]int{0, 1, 2, 3, 4, 5, 6, 7, 8}fmt.Println("-------slice")s1 := arr[2:]fmt.Println("s1 : ", s1)s2 := arr[:]fmt.Println("s2 : ", s2)// 切片是引用传递的fmt.Println("After updateSlice(s1)")updateSlice(s1)fmt.Println(s1)fmt.Println(arr)fmt.Println("After updateSlice(s2)")updateSlice(s2)fmt.Println(s2)fmt.Println(arr)
}
输出结果:
-------slice
s1 : [2 3 4 5 6 7 8]
s2 : [0 1 2 3 4 5 6 7 8]
After updateSlice(s1)
[100 3 4 5 6 7 8]
[0 1 100 3 4 5 6 7 8]
After updateSlice(s2)
[100 1 100 3 4 5 6 7 8]
[100 1 100 3 4 5 6 7 8]
- 切片自切
- 切片自切的案例
func main() {arr := [...]int{0, 1, 2, 3, 4, 5, 6, 7, 8}s2 := arr[:]fmt.Println("Reslice") // 自切fmt.Println(s2)s2 = s2[:5]fmt.Println(s2)s2 = s2[2:]fmt.Println(s2)
}
输出结果
Reslice
[0 1 2 3 4 5 6 7 8]
[0 1 2 3 4]
[2 3 4]
- 切片扩展
slice可以向后扩展,不可以向前扩展;
切片的长度len是它所包含的元素个数。
切片的容量cap是从它的第一个元素开始数,到其底层数组元素末尾的个数
s[i]不可以超越len(s),向后扩展可以超越len(s)但不可以超越底层数组cap(s),如下例;
切片扩展的案例
func main(){fmt.Println("Extending slice") // slice 的扩展arr1 := [...]int{0, 1, 2, 3, 4, 5, 6, 7, 8}s1 = arr1[2:6] // s1中有4个元素,但切片扩展的元素的个数为4+3(隐藏的元素个数)=7个s2 = s1[3:6] // [ s1[3], s1[4], s1[5] ] 向后扩展了// var _ int = s1[4] // 报错,数组下标越界 runtime error: index out of range [4] with length 4// 切片能读取后面隐藏的元素即扩展元素,数组不能读取到隐藏的元素fmt.Printf("arr1 = %v, len(arr1) = %d\n", arr1, len(arr1))fmt.Printf("s1 = %v, len(s1) = %d, cap(s1) = %d\n", s1, len(s1), cap(s1))fmt.Printf("s2 = %v, len(s2) = %d, cap(s2) = %d\n", s2, len(s2), cap(s2))
}
输出结果:
Extending slice
arr1 = [0 1 2 3 4 5 6 7 8], len(arr1) = 9
s1 = [2 3 4 5], len(s1) = 4, cap(s1) = 7
s2 = [5 6 7], len(s2) = 3, cap(s2) = 4
- Slice的创建
创建方法一:同定义未初始化的数组一样但不写明长度
创建方法二:同边定义边初始化的数组一样但不写明长度
创建方法三:使用 make() 定义Slice
创建Slice的案例
func printSlices(s []int) {fmt.Printf("%v, len = %d, cap = %d\n",s, len(s), cap(s))
}
func main() {fmt.Println("Create Slice")// 创建方法一var s []int // Zero value for slice is nil// 此时 s == nillfor i := 0; i < 100; i++{printSlices(s)s = append(s, 2 * i + 1)}fmt.Println(s)fmt.Println("--------------")// 创建方法二s1 := []int{2, 4, 6, 8} // len = 4, cap = 4printSlices(s1)// 创建方法三s2 := make([]int, 15) // len = 15, cap = 15s3 := make([]int, 10, 32) // len = 10, cap = 32// s2, s3为初始化,都赋值默认值0printSlices(s2)printSlices(s3)
}
部分输出结果:
...
--------------
[2 4 6 8], len = 4, cap = 4
[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0], len = 15, cap = 15
[0 0 0 0 0 0 0 0 0 0], len = 10, cap = 32
- 向Slice添加元素
添加元素时如果超越cap,系统会重新分配更大的底层数组;
又要值传递的关系,必须接受append的返回值;
s = append(s, val)
添加元素
func main(){arr1 := [...]int{0, 1, 2, 3, 4, 5, 6, 7, 8}s1 = arr1[2:6]s2 = s1[3:6]s3 := append(s2, 10)s4 := append(s3, 11)s5 := append(s4, 12)fmt.Println("s3, s4, s5 = ", s3, s4, s5)// s4 and s5 no longer view arr1fmt.Println("arr1 = ", arr1)
}
输出结果:
append slice
s3, s4, s5 = [5 6 7 10] [5 6 7 10 11] [5 6 7 10 11 12]
arr1 = [0 1 2 3 4 5 6 7 10]
// 其中s4, s5的底层数组不知道在哪里
注
向Slice进行append操作时,可能需要更换新底层数组,从而导致Slice的ptr,len,cap都变更,需要新的Slice来接受这三个值;
- Slice的复制
通过系统内建函数 copy() 来实现。
Slice复制的案例
func main(){s1 := []int{2, 4, 6, 8}s2 := make([]int, 15)printSlices(s1)printSlices(s2)fmt.Println("Copying slice")copy(s2, s1) // 将s1复制到s2上printSlices(s2)
}
输出结果:
[2 4 6 8], len = 4, cap = 4
[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0], len = 15, cap = 15
Copying slice
[2 4 6 8 0 0 0 0 0 0 0 0 0 0 0], len = 15, cap = 15
- Slice元素的删除
Go中无内建删除函数;
利用append()函数进行删除操作;
s = append(s[:index], s[index+1:]…);
Slice元素的删除的案例
func main(){s1 := []int{2, 4, 6, 8}s2 := make([]int, 15)copy(s2, s1) printSlices(s2)fmt.Println("Deleting elements from slice")// 删除下标为3的元素s2 = append(s2[:3], s2[4:]...) // append的第二个参数是可变参数printSlices(s2)// 删除切片首元素fmt.Println("Popping from front")font := s2[0]s2 = s2[1:]fmt.Println("front = ", font)printSlices(s2)// 删除切片尾元素fmt.Println("Popping from back")back := s2[len(s2) - 1]s2 = s2[:len(s2) - 1]fmt.Println("back = ",back)printSlices(s2)
}
输出结果:
[2 4 6 8 0 0 0 0 0 0 0 0 0 0 0], len = 15, cap = 15
Deleting elements from slice
[2 4 6 0 0 0 0 0 0 0 0 0 0 0], len = 14, cap = 15
Popping from front
front = 2
[4 6 0 0 0 0 0 0 0 0 0 0 0], len = 13, cap = 14
Popping from back
back = 0
[4 6 0 0 0 0 0 0 0 0 0 0], len = 12, cap = 14
注
cap表示是slice中ptr到底部数组最后一个元素之间元素个数
利用append删除中间元素时,底部数组并没有改变,故cap=15,由于少一个元素,长度len=14;
删除slice的首元素,需要slice的ptr向后移动一位,故cap=14,由于少一个元素,长度len=13;
删除slice的尾元素,没有影响ptr,以及底部数组不变,故cap=14,由于少一个元素,长度len=12;
上述过程中s2的物理地址没有发送变化
键值对(Map)
- Map的结构:map[K]V,键为K 值为V;
- Map的复合结构:map[K1]map[K2]V, 外面的map的 键为K1 值为map,里面的map的 键为K2 值为V;
- Map创建
- 创建方式一:map [ 键类型 ] 值类型 { “键名” : “值” }
- 创建方式二:make ( map [ 键类型 ] 值类型 )
- 创建方法三:var Map名 map [ 键类型 ] 值类型
- 创建案例
func main(){// map构建方法一m := map[string]string {"name" : "ccmouse","course" : "Golang","sit" : "immoc","quality" : "notbad",}fmt.Println(m)// map构建方法二m2 := make(map[string]int) // 空的,未初始化 m2 == emptyfmt.Println(m2)// map构建方法三var m3 map[string]int // m3 == nilfmt.Println(m3)
}
输出结果:
map[course:Golang name:ccmouse quality:notbad sit:immoc]
map[]
map[]
- Map的遍历
- 使用range遍历key,或者遍历key,value对;
- 不保证遍历顺序,如需顺序,需要手动对key排序;
- map中的元素是无序的, 每次遍历顺序是不一样;
- 使用len获得map的元素个数;
- map使用哈希表,必须可以比较相等;
- 除了slice,map,function的内建类型都可以作为key;
- 自定义类型Struct不包含上述字段,也可作为key;
- 遍历案例
func main(){m := map[string]string {"name" : "ccmouse","course" : "Golang","sit" : "immoc","quality" : "notbad",}// map遍历fmt.Println("------Traversing map------")for k, v := range m {fmt.Println(k, v)}// 只要kfmt.Println("------Only need K------")for k := range m {fmt.Println(k)}// 只要vfmt.Println("------Only need V------")for _, v := range m {fmt.Println(v)}// 每次遍历顺序不一样,map中的元素是无序的
}
输出结果:
------Traversing map------
name ccmouse
course Golang
sit immoc
quality notbad
------Only need K------
sit
quality
name
course
------Only need V------
ccmouse
Golang
immoc
notbad
- 获得Map中的元素
- 获取元素:m [ key ]
- key不存在时,获得Value类型的初始值
- 通过键获取对应值的案例
func main(){m := map[string]string {"name" : "ccmouse","course" : "Golang","sit" : "immoc","quality" : "notbad",}fmt.Println("------Getting values------")courseName := m["course"]fmt.Println(courseName)causeName := m["cause"] // m中不存在cause键fmt.Println(causeName) // 获取不存在键对应的值时,输出结果是空的,这里是空串
}
输出结果:
------Getting values------
Golang
- 用value, ok := m [ key ] 来判断是否存在key
- 判断元素是否存在map的案例
func main(){m := map[string]string {"name" : "ccmouse","course" : "Golang","sit" : "immoc","quality" : "notbad",}// 判断k是否在map中if caseName, ok := m["case"]; ok { // m中不存在casefmt.Println(caseName)}else {fmt.Println("key does not exist")}
}
输出结果:
key does not exist
- 删除map中的元素
func main(){m := map[string]string {"name" : "ccmouse","course" : "Golang","sit" : "immoc","quality" : "notbad",}// 删除map中的元素,使用内建函数delete()fmt.Println("------Deleting values------")name, ok := m["name"]fmt.Println(name, ok)delete(m, "name")name, ok = m["name"]fmt.Println(name, ok)
}
输出结果:
------Deleting values------
ccmouse truefalse
字符和字符串处理
- 使用range遍历pos,rune对;
- 使用utf8.RuneCountInString获得字符数量;
- len(string)只是获得字节数
- 使用[]byte获得字节;
- byte转为rune就不需要考虑UTF-8编码问题;
- 字符串处理案例
func main() {s := "Yes我爱慕课网!"fmt.Println(len(s))for _, b := range []byte(s) {fmt.Printf("%X ", b)}fmt.Println()// UTF-8 可变长//一个英文占一个字节,一个中文占三个字节for i, ch := range s { // ch is a rune 四字节的int型(int32)// UTF-8转为Unicodefmt.Printf("(%d, %X) ", i, ch)}fmt.Println()fmt.Println("Rune count:",utf8.RuneCountInString(s))bytes := []byte(s)for len(bytes) > 0 {ch, size := utf8.DecodeRune(bytes) // 英文字符的size是1,中文的字符size是3bytes = bytes[size:]fmt.Printf("%c ", ch)}fmt.Println()// 将字符串转runefor i, ch := range []rune(s) {// 重新开了一个rune数组fmt.Printf("(%d %c) ", i, ch)}fmt.Println()
}
输出结果:
19
59 65 73 E6 88 91 E7 88 B1 E6 85 95 E8 AF BE E7 BD 91 21
(0, 59) (1, 65) (2, 73) (3, 6211) (6, 7231) (9, 6155) (12, 8BFE) (15, 7F51) (18, 21)
Rune count: 9
Y e s 我 爱 慕 课 网 !
(0 Y) (1 e) (2 s) (3 我) (4 爱) (5 慕) (6 课) (7 网) (8 !)
strings包中的各种操作方法;
Fields,Split,Join
- Fields 空格分割
func Fields (s string) []string
- 返回将字符串按照空格(连续的空格被认为一个空格进行分割)分割的多个字符串。如果字符串全部是空格或者是空字符串的话,会返回空切片。
- example
fmt.Printf("Fields are: %q", strings.Fields(" foo bar baz "))
- output
Fields are: ["foo" "bar" "baz"]
- Split 以sep为分割符分割
func Split(s, sep string) []string
以指定的分隔符拆分,返回一组切片;
用去掉s中出现的sep的方式进行分割,会分割到结尾,并返回生成的所有片段组成的切片(每一个sep都会进行一次切割,即使两个sep相邻,也会进行两次切割)。如果sep为空字符,Split会将s切分成每一个unicode码值一个字符串。
example
fmt.Printf("%q\n", strings.Split("a,b,c", ","))
fmt.Printf("%q\n", strings.Split("a man a plan a canal panama", "a "))
fmt.Printf("%q\n", strings.Split(" xyz ", ""))
fmt.Printf("%q\n", strings.Split("", "Bernardo O'Higgins"))
- output
["a" "b" "c"]
["" "man " "plan " "canal panama"]
[" " "x" "y" "z" " "]
[""]
- Join连接
func Join(a []string, sep string) string
- 将一系列字符串连接为一个字符串,之间用sep来分隔;
- example
s := []string{"foo", "bar", "baz"}
fmt.Println(strings.Join(s, ", "))
- output
foo, bar, baz
Contains,Index
- Contains判断是否包含子串
func Contains(s, substr string) bool
- 判断字符串s是否包含子串substr。
- exmaple
fmt.Println(strings.Contains("seafood", "foo"))
fmt.Println(strings.Contains("seafood", "bar"))
fmt.Println(strings.Contains("seafood", ""))
fmt.Println(strings.Contains("", ""))
- ouput
true
false
true
true
- Index查找位置
func Index(s, sep string) int
- 子串sep在字符串s中第一次出现的位置,不存在则返回-1。
- exmaple
fmt.Println(strings.Index("chicken", "ken"))
fmt.Println(strings.Index("chicken", "dmr"))
- output
4
-1
ToLower, ToUpper
- ToLower字母小写
func ToLower(s string) string
- 返回将所有字母都转为对应的小写版本的拷贝。
- exmaple
fmt.Println(strings.ToLower("Gopher"))
- output
gopher
- ToUpper字母大写
func ToUpper(s string) string
返回将所有字母都转为对应的大写版本的拷贝
exmaple
fmt.Println(strings.ToUpper("Gopher"))
- output
GOPHER
Trim,TrimRight,TrimLeft
- Trim
func Trim(s string, cutset string) string
返回将s前后端所有cutset包含的utf-8码值都去掉的字符串。
exmaple
fmt.Printf("[%q]", strings.Trim(" !!! Achtung! Achtung! !!! ", "! "))
- output
["Achtung! Achtung"]
- TrimLeft
func TrimLeft(s string, cutset string) string
- 返回将s前端所有cutset包含的utf-8码值都去掉的字符串。
- TrimRight
func TrimRight(s string, cutset string) string
- 返回将s后端所有cutset包含的utf-8码值都去掉的字符串。
Go内建容器——Golang学习笔记3相关推荐
- golang学习笔记之--Go语言内建容器
话接上文 <golang学习笔记之--Go语言基本语法> 今天继续记录学习笔记,今天的笔记主题是Go语言内建容器 如果各位童鞋想要获得下面的源码,请搜索gzh:隔壁王小猿,关注后回复&qu ...
- golang学习笔记(基础篇)
LCY~~Golang学习笔记 一.Go语言开发环境 ##安装Go开发包以及VsCode Go开发包与vscode配置安装教程网址:https://www.liwenzhou.com/posts/Go ...
- 118云原生编程语言Golang学习笔记
Golang学习笔记 文章目录 1.Go简介 1.1 简介 1.2 设计初衷 1.3 Golang vs Java 1.4 应用领域 1.5 用go语言的公司 2.Go下载和安装 2.1 开发工具 2 ...
- golang学习笔记(五):数组的定义和使用
golang 学习笔记 数组定义 数组是一系列相同数据类型在内存中有序存储的数据集合 var 数组名 [元素个数]数据类型//定义了10个整型变量的数组元素var arr [10]int//通过下标找 ...
- Golang学习笔记之GORM基础使用(二)
本文章主要学习GORM的增删查改.若还没有完成数据库和数据表的创建.定义模型以及数据库的连接请先学习本本专栏文章Golang学习笔记之GORM基础使用(一).本文为学习笔记,通过GORM官方中文文档和 ...
- golang学习笔记8 beego参数配置 打包linux命令
golang学习笔记8 beego参数配置 打包linux命令 参数配置 - beego: 简约 & 强大并存的 Go 应用框架 https://beego.me/docs/mvc/contr ...
- golang学习笔记12 beego table name `xxx` repeat register, must be unique 错误问题
golang学习笔记12 beego table name `xxx` repeat register, must be unique 错误问题 今天测试了重新建一个项目生成新的表,然后复制到旧的项目 ...
- golang学习笔记(十六):多态的实现
golang 学习笔记 多态实现 package main import "fmt"//先定义接口 在根据接口实现功能 type Humaner1 interface {//方法 ...
- golang学习笔记-1
golang学习笔记-1 自学golang时,找到一篇学习资料http://golang.iswbm.com/en/latest/c01/c01_08.html 初看上面两种写法,不明就里,哪里高级了 ...
最新文章
- SMO学习笔记(二)——还原(恢复)篇之完整恢复
- centos7配置br0_centos 7.2 网卡配置文件 及 linux bridge的静态配置
- python自学教程 pdf-《Python编程从入门到精通》PDF高清完整版-PDF下载
- Today's my MDX...
- Physical Standby Databases Role Transfer
- matlab绘图基础,matlab绘图基础
- windows xp共享访问提示“拒绝访问”的故障处理步骤
- 1093-A+B for Input-Output Practice (V)
- 远方的人 -- 龙瑜
- 得到APP之订阅专栏《硅谷来信》和《精英日课》目录
- 50种让你的网站被关注的方法
- 7-13 寻找大富翁 (25分)
- 陕南柿子红了_陕南赤子_新浪博客
- 基层管理者的第一步——从“我”变成“我们”
- c++中如何把任意类型的指针转化为void*
- L298N驱动俩路电机按键控制正反转
- 常见网络摄像机(摄像头)的端口及RTSP地址
- 统计图配色方案_填充
- android 监听短信并获取验证码
- 极光开发者周刊【No.0730】
热门文章
- 虚拟偶像,人类探索元宇宙的萌芽
- 【ZBrush雕刻】3D机械模型!LOL英雄联盟“烬”教程分享
- Android应用卸载器
- ArGIS Engine专题(2)之地图同步
- 当医药保健遇见“互联网+”和数据,就可以赢得整个江湖
- 什么东西可以改善睡眠,这些助眠好物让你远离失眠
- python-读取excel文件
- arcgis engine 将图层要素复制到另一个图层
- 提升开发效率N倍的20+命令行神器!(附 demo)
- 【HDU No. 1166】 敌兵布阵