GO入门——4. 数组、切片与map

1. 数组

  • 定义数组的格式:var [n],n>=0
  • 数组长度也是类型的一部分,因此具有不同长度的数组为不同类型
  • 注意区分指向数组的指针和指针数组
    //数组的指针
    a := [2]int{1, 2}
	p := &a
	fmt.Println(p)  //&[1 2]
	
	//指针数组
	x, y := 1, 2
	b := [2]*int{&x, &y}    //[0xc042034208 0xc042034220]
	fmt.Println(b)
  • 数组在Go中为值类型
  • 数组之间可以使用==或!=进行比较,但不可以使用<或>
  • 可以使用new来创建数组,此方法返回一个指向数组的指针
  • Go支持多维数组
	a := [2][3]int{
		{1, 2, 3},
		{4, 5, 6}}  //最后的}必须在这一行
	fmt.Println(a)  //[[1 2 3] [4 5 6]]
	//长度不同的数组类型不同
	var a [2]int
	var b [1]int
	// a = b	编译错误:cannot use b (type [1]int) as type [2]int in assignment

	//直接赋值
	c := [2]int{1}             //第一个为1,第二个默认为0
	d := [20]int{10: 1, 19: 2} //指定固定位置的值

	//系统推断类型(长度)
	e := [...]int{1, 2, 3}
	f := [...]int{1, 2, 3, 19: -1}

	//通过new创建指向数组的指针,都可以通过[]来获取和设置数组元素
	p1 := new([2]int)
	p1[1] = 1
	fmt.Println(p1)	//&[0 1]
	p2 := [2]int{}
	p2[1] = 1	//[0 1]
	fmt.Println(p2)

2. 切片

  • 其本身并不是数组,它指向底层的数组

  • 作为变长数组的替代方案,可以关联底层数组的局部或全部
    为引用类型

  • 可以直接创建或从底层数组获取生成

  • 使用len()获取元素个数,cap()获取容量

  • 一般使用make()创建

  • 如果多个slice指向相同底层数组,其中一个的值改变会影响全部

  • make([]T, len, cap)

  • 其中cap可以省略,则和len的值相同

  • len表示存数的元素个数,cap表示容量

2.1 reslice

  • Reslice时索引以被slice的切片为准
  • 索引不可以超过被slice的切片的容量cap()值
  • 索引越界不会导致底层数组的重新分配而是引发错误

2.2 append

  • 可以在slice尾部追加元素
  • 可以将一个slice追加在另一个slice尾部
  • 如果最终长度未超过追加到slice的容量则返回原始slice
  • 如果超过追加到的slice的容量则将重新分配数组并拷贝原始数据
//数组
	a := [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9}
	//slice
	var s []int
	//取从[5,len(a))的值放入slice
	s = a[5:]
	fmt.Println(s) //[6 7 8 9 0]
	s[1] = 10      //slice是共享数组的,因此修改slice数组也会修改
	fmt.Println(s) //[6 10 8 9 0]
	fmt.Println(a) //[1 2 3 4 5 6 10 8 9 0]
	//make的三个参数表示类型、len和cap
	//当长度超过cap时,该slice的cap将乘以2将内存换一个位置,并将原始数据复制过去
	ss := make([]int, 2, 3)
	for i := 0; i < 10; i++ {
		s1 := append(ss, i) //append的返回值需要注意,当赋值给新的slice时,ss将永远不会改变
		fmt.Println(len(ss), cap(ss), ss)
		fmt.Println(len(s1), cap(s1), s1)
	}

	//当slice重新分配内存后,对其值的修改不会影响到之前共享的数组
	s2 := a[:2]
	fmt.Println(s2)
	s2 = append(s2, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3)
	s2[0] = 100
	fmt.Println(a) //[1 2 3 4 5 6 10 8 9 0]

	//copy,当长的复制到短的时只复制短的个数,当短的复制到长的时将短的完全复制到长的中
	s3 := []int{1, 2, 3, 4, 5, 6}
	s4 := []int{7, 8, 9}
	copy(s3, s4)	//将s4复制到s3
	fmt.Println(s3) //[7 8 9 4 5 6]
	s3 = []int{1, 2, 3, 4, 5, 6}
	copy(s4, s3)
	fmt.Println(s4)	//[1 2 3]

3 map

  • 类似其它语言中的哈希表或者字典,以key-value形式存储数据

  • Key必须是支持==或!=比较运算的类型,不可以是函数、map或slice

  • Map查找比线性搜索快很多,但比使用索引访问数据的类型慢100倍

  • Map使用make()创建,支持 := 这种简写方式

  • make([keyType]valueType, cap),cap表示容量,可省略

  • 超出容量时会自动扩容,但尽量提供一个合理的初始值

  • 使用len()获取元素个数

  • 键值对不存在时自动添加,使用delete()删除某键值对

  • 使用 for range 对map和slice进行迭代操作

//声明与赋值,[]中为key类型,其后为value
	var m map[string]int
	m = map[string]int{}

	//通过make创建与声明
	var m1 = make(map[int]string)
	m2 := make(map[int]string)
	//对k-v取值与设值
	m1[1] = "ok"
	fmt.Println(m1[1]) //ok
	delete(m1, 1)      //删除key
	fmt.Println(m1[1]) //空
	//多返回
	a, ok := m1[2]
	if !ok {
		fmt.Println("没有key=2的value") //输出
	}
	fmt.Println(a, ok) //当不存在key时会返回空,ok=false
	//复杂map
	var mf map[int]map[string]int
	mf = make(map[int]map[string]int) //初始化最外层map
	mf[1] = make(map[string]int)      //初始化map[1]中的map,仅仅初始化key=1的map
	mf[1]["ok"] = 3
	fmt.Println(mf[1]["ok"])

4 range

//对于slice,i,v分别为index和slice下标对应的值,可以采用_将值忽略
	s := []int{1, 2, 3}
	for i, v := range s {
		fmt.Println(i, v)
		v = 10   //i,v为值的拷贝,修改不影响slice
		s[i] = 0 //直接修改了slice
	}
	fmt.Println(s) //输出[0 0 0]

	//对于map,k,v即为map中的key,value
	//每次range的顺序可能不一样
	m := map[int]string{
		1: "ok"}
	for k, v := range m {
		fmt.Println(v)
		m[k] = "okok"	//修改map中值也只能通过对m进行直接操作
	}
	fmt.Println(m)	//map[1:okok]
原文地址:https://www.cnblogs.com/suolu/p/6714275.html