Go语言基础知识2——内建容器

一、数组

数组定义

var arr [5]int:变量个数在前,变量类型在后

	var arr1 [5]int
	arr2 := [3]int{1, 3, 5}          //需赋初值
	arr3 := [...]int{2, 4, 6, 8, 10} //数量由初始值决定
	var grid [4][5]int               //二维数组,4行5列

range关键字

	//通过range关键字可以同时获得索引及其对应元素
	//for _,v:= range arr3 通过_省略变量
	//如果只要i,可写成for i:=range arr3
	for i,v :=range arr3{
		fmt.Println(i,v)
	}

数组是值传递

[10]int 和 [20]int 是不同类型

调用func f(arr [10]int)会拷贝数组 (其他大部分语言传数组都是引用传递),

通过指针可以修改数组的值

//通过指针可以修改数组的值
func printArray(arr *[5]int){
	for i,v :=range arr{
		fmt.Println(i,v)
	}
	arr[0]=100 //不需要加*
}

//调用函数的时候要用&arr1,不像C语言数组名就是首地址
printArray(&arr1)

Go语言中一般不直接使用数组


二、Slice(切片)

Slice区间前闭后开

arr[2:6]、arr[:6]、arr[2:]、arr[:]都是切片

func main() {
	arr := [...]int{0, 1, 2, 3, 4, 5, 6, 7}
	fmt.Println("arr[2:6] =", arr[2:6]) //2,3,4,5
	fmt.Println("arr[:6] =", arr[:6])   //0,1,2,3,4,5
	fmt.Println("arr[2:] =", arr[2:])   //2,3,4,5,6,7
	fmt.Println("arr[:] =", arr[:])     //0,1,2,3,4,5,6,7
}

Slice本身没有数据,是对底层array的一个view

arr := [...]int{0,1,2,3,4,5,6,7}
s := arr[2:6]
s[0] = 10
// array变为[0,1,10,3,4,5,6,7]

Reslice
对slice再求slice

	arr := [...]int{0, 1, 2, 3, 4, 5, 6, 7}
	s1 := arr[2:5]
	fmt.Println(s1) //2,3,4
	s1 = s1[1:3]
	fmt.Println(s1) //3,4

Slice的扩展

在以下示例中,s1为[2,3,4,5],如果直接取s1[4]会产生越界错误

使用s2再取s1的切片s1[3:5],则不会报错

	arr := [...]int{0, 1, 2, 3, 4, 5, 6, 7}
	s1 := arr[2:6] //2,3,4,5
	s2 := s1[3:5]  //5,6

在这里插入图片描述

在这里插入图片描述
slice可以向后扩展,不可以向前扩展
s[i]不能超过len(s),向后扩展可以超过len(s)不可以超过cap(s)

func main() {
	arr := [...]int{0, 1, 2, 3, 4, 5, 6, 7}
	s1 := arr[2:6]                //2,3,4,5
	fmt.Println(len(s1), cap(s1)) //4,6
	s2 := s1[3:5]                 //5,6
	fmt.Println(len(s2), cap(s2)) //2,3
}

Slice的操作

向Slice添加元素

func main() {
	arr := [...]int{0, 1, 2, 3, 4, 5, 6, 7}
	s1 := arr[2:6]       //2,3,4,5
	s2 := s1[3:5]        //5,6
	s3 := append(s2, 10) //5,6,10
	s4 := append(s3, 11) //5,6,10,11
	s5 := append(s4, 12) //5,6,10,11,12
	//arr数组为[0,1,2,3,4,5,6,10]
}

切片在添加元素时如果超越cap,那么就不再是对原数组的view,系统会重新分配更大的底层数组
由于值传递的关系,在append时slice的len和cap都有可能改变,必须接受append的返回值 s=append(s,val)


创建Slice

	var s []int //Zero value for slice is nil; len = 0; cap = 0

	s1 := []int{2, 4, 6, 8, 10}

	s2 := make([]int, 16)
	s3 := make([]int, 10, 32)//type,len,cap

copy

	//只copy数值
	arr := []int{0, 1, 2, 3, 4, 5, 6, 7}
	s1 := arr[2:6]        //[2 3 4 5]
	s2 := make([]int, 10) //[0 0 0 0 0 0 0 0 0 0]
	copy(s2, s1)
	fmt.Println(s1, s2) //[2 3 4 5] [2 3 4 5 0 0 0 0 0 0]

delete

删除元素没有内建函数

	//删除下标为3的元素
	s2=append(s2[:3],s2[4:]...)//使用...将Slice解开逐个append 
	//删除头
	s2=s2[1:]
	//删除尾
	s2=s2[:len(s2) - 1]

三、Map

map定义:map[Key]Value{},方括号中是key的类型,后面跟value的类型,大括号中加初始化的值

复合map:map[K1]map[K2]V,外层map的key为K1,value为map[K2]V

创建

	m := map[string]string{
		"name":    "ccmouse",
		"course":  "golang",
		"site":    "imooc",
		"quality": "notbad",
	}

	m2 := make(map[string]int) //m2 == empty map

	var m3 map[string]int //m3 == nil

遍历

使用range遍历
使用len获得元素个数

	//遍历,Map使用哈希表元素无序,每次输出的顺序都不同
	//如需顺序,需要手动对key排序,全取出来加到slice中
	for k, v := range m {
		fmt.Println(k, v)
	}

取元素,判断是否存在

	//取元素,判断元素是否存在,若存在ok为true,否则为false
	//key不存在时获得元素类型的初始值
	courseName, ok := m["course"]
	fmt.Println(courseName, ok) //golang true
	causeName, ok := m["cause"]
	fmt.Println(causeName, ok) // false,键不存在输出为空

删除元素

	delete(m,"name")

map中的key
map使用哈希表,key必须可以比较相等
除了slice,map,function的内建类型都可以作为key
struct类型不包含上述字段,也可作为key


四、字符串

字符串的实现

range []byte(s):使用[]byte获得字节(底层),字符串采用utf-8编码,英文一字节,中文三字节,直接输出s[idx]获得的是字符串对应位置的字节

range s:获得的是字符的Unicode编码

字符串的不同输出形式

字符串Yes!
UTF-8(range []byte(s))596573E6 88 91E7 88 B1E6 85 95E8 AF BEE7 BD 9121
Unicode(range s)0,591,652,733,62116,72319,615512,8BFE15,7F5118,21
range []rune(s)0,591,652,733,62114,72315,61556,8BFE7,7F518,21

Ps,后两行为:下标,字符;
即range s中每个中文字符占三个长度,因为字符串底层是由字节存储的,每个中文字符占三个字节,所以占三个长度
[]rune(s)中每个中文字符占一个长度,一个rune类型占四个字节,所以一个rune可以存储一个字符,

	s := "Yes我爱慕课网!"
	for i, b := range []byte(s) {
		fmt.Printf("(%d %X)", i, b)
	}
	fmt.Println()
	//结果
	//(0 59)(1 65)(2 73)(3 E6)(4 88)(5 91)(6 E7)(7 88)(8 B1)(9 E6)(10 85)(11 95)(12 E8)(13 AF)(14 BE)(15 E7)(16 BD)(17 91)(18 21)
	for i, ch := range s { //ch is a rune
		fmt.Printf("(%d %X)", i, ch)
	}
	fmt.Println()
	//结果 utf8转为Unicode
	//(0 59)(1 65)(2 73)(3 6211)(6 7231)(9 6155)(12 8BFE)(15 7F51)(18 21)

len:返回字节长度
utf8.RuneCountInString:返回字符个数

	fmt.Println(len(s))//19
	fmt.Println(utf8.RuneCountInString(s))//9

使用utf8.DecodeRune解码

func DecodeRune(p []byte) (r rune, size int) {}:
输入为UTF-8编码的字节,输出为rune以及字符的所占的字节数,使用%c获得字符,汉字每三个字节进行解码

	bytes:=[]byte(s)
	for len(bytes)>0{
		ch,size:=utf8.DecodeRune(bytes)
		fmt.Printf("%c ",ch)
		bytes=bytes[size:]
	}
	//结果
	//Y e s 我 爱 慕 课 网 ! 

顶层使用:将s转为[]rune下标从0递增
[]rune转换并不是对内存的重新理解,而是会将字节进行解码,将转换后的字符存放在一个新开的rune slice里面

	for i,ch:=range []rune(s){  //ch is a rune
		fmt.Printf("(%d %c)",i,ch)
	}
	//结果
	//(0 Y)(1 e)(2 s)(3 我)(4 爱)(5 慕)(6 课)(7 网)(8 !)

字符串的有关操作

字符串的有关操作都在strings包中

	//字符串分隔、拼接
	fmt.Println(strings.Fields("a    b c d"))//[a b c d] 空格分割
	fmt.Println(strings.Split("abcbde","b"))//[a c de]
	fmt.Println(strings.Join([]string{"aa","bb","cc"},"A"))//aaAbbAcc

	//子串查找
	fmt.Println(strings.Index("abcec","c"))//2
	fmt.Println(strings.Contains("abcec","c"))//true

	//大小写转换
	fmt.Println(strings.ToLower("AAA"))//aaa
	fmt.Println(strings.ToUpper("aaAb"))//AAAB

	//切割首尾字符
	fmt.Println(strings.Trim("abcdaaa","abc"))//d
	fmt.Println(strings.TrimLeft("abcdaaa","abc"))//daaa
	fmt.Println(strings.TrimRight("abcdaaa","abc"))//abcd
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值