golang之slice、array、map

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/phantom_111/article/details/79466920

Array

array是固定长度的数组,使用前必须确定数组长度。所以动态数组slice更通用。数组是一个值类型 ,可以直接用它来进行赋值操作,但是数组的类型同时包括数组的长度和元素类型 ,数组类型完全相同才能相互赋值。

array 声明和初始化

//声明一个长度为10的int类型的数组
var array0 [10]int   

//声明并初始化
var array1 [5]int = [5]int{1,2,3,4,5}

//声明并未索引(0开始)为1和4位置指定元素初始化
//剩余位置为0
var array2 [5]int = [5]int{1:1,4:5}

//声明并初始化
array3 :=[5]int{}

//go编译器推导数组长度2
 array4 :=[...]{1,2}

//二维数组
var array5 [2][2]int

array的使用

使用[]操作符

go
array :=[2]int{1,2}
array[1] = 1

使用range关键字

for i, v := range a {
    fmt.Printf("d% %d\n", i, v)
}

注意: 迭代过程中v是索引位置值的拷贝,因此变量v的地址每次循环都是相同的。 如果要得到每个元素的真实地址可以用&a[i]

特点总结

  • golang中的数组是值类型,也就是说,如果你将一个数组赋值给另外一个数组,那么,实际上就是整个数组拷贝了一份。
  • 如果golang中的数组作为函数的参数,那么实际传递的参数是一份数组的拷贝,而不是数组的指针。
  • array的长度也是Type的一部分,这样就说明[10]int[20]int是不一样的。

slice

slice基于数组构建,但是提供更强的功能。slice是引用类型,作为函数参数传递时,可以直接在函数内部修改,函数外部是可见的。 slice可以认为是动态数组。

声明和初始化

内建函数make创建slice

//指定slice长度,这是容量默认为长度
var slice1 = make([]int,5)
//同时指定长度3和容量5
var slice2 = make([]int,3,5)
//长度不允许大于容量

直接赋值的方式创建

// 创建一个字符串 slice
// 长度和容量都是 5
slice := []string{"Red", "Blue", "Green", "Yellow", "Pink"}

// 创建一个字符串 slice
// 初始化一个有100个元素的空的字符串 slice
slice := []string{99: ""}

基于数组创建

months := [...]string{1: "January", /* ... */, 12:"December"}
Q2 := months[4:7] // ["April", "May", "June"], len=3, cap=9
summer := months[6:9] // ["June", "July", "August"], len=3, cap=7

empty slice和nil slice

//创建nil slice
var slice []int

//创建empty slice
slice1 :=make([]int,0)
//or
slice2 :=[]int{}
fmt.Println(slice1==nil, slice2==nil, slice3==nil)
//结果ture, false, false
  • 二者是非常容易混淆的概念,原因是长度和容量都是0。区别在于nil slice没有底层数组的,nil slice被看作是未被初始化的slice。
  • nil slice通常用于表示一个并不存在的slice,比如返回slice的函数中发生异常的时候。
  • empty slice通常用于表示一个空集合,比如一个数据库查询返回0个结果。
  • 判断slice是否为空时,应该用len(s) == 0。

append()和copy()函数

以下代码描述从拷贝切片的copy方法和向切片追加新元素的append方法的使用:

package main

import "fmt"

func main() {
   var numbers []int
   printSlice(numbers)

   /* 允许追加空切片 */
   numbers = append(numbers, 0)
   printSlice(numbers)

   /* 向切片添加一个元素 */
   numbers = append(numbers, 1)
   printSlice(numbers)

   /* 同时添加多个元素 */
   numbers = append(numbers, 2,3,4)
   printSlice(numbers)

   /* 创建切片 numbers1 是之前切片的两倍容量*/
   numbers1 := make([]int, len(numbers), (cap(numbers))*2)

   /* 拷贝 numbers 的内容到 numbers1 */
   copy(numbers1,numbers)
   printSlice(numbers1)   
}

func printSlice(x []int){
   fmt.Printf("len=%d cap=%d slice=%v\n",len(x),cap(x),x)
}

执行结果:

len=0 cap=0 slice=[]
len=1 cap=1 slice=[0]
len=2 cap=2 slice=[0 1]
len=5 cap=6 slice=[0 1 2 3 4]
len=5 cap=12 slice=[0 1 2 3 4]

写出以下代码的执行结果:

go
// 创建一个长度和容量都为5的 slice
slice := []int{1, 2, 3, 4, 5}
// 创建一个新的 slice
newSlice := slice[1:3]
// 为新的 slice append 一个值
newSlice = append(newSlice, 6)
fmt.Println("slice", slice, "newSlice", newSlice)

执行结果:

slice [1 2 3 6 5] newSlice [2 3 6]

注: 重叠的slice会共享底层的数组,所以在未超过容量的条件下,append的新值在改变newSlice的值的同时也改变了slice的值。

​ 对于容量不足的slice,append则会创建新的底层数组,拷贝已存在的值和将要被附加的新值。如果元素个数小于1000,容量会是现在元素的2倍;如果元素个数超过1000,容量则会以1.25倍来增长。

特点总结:

  • slice是一个引用类型,是一个动态的指向数组切片的指针。
  • slice是一个不定长的,总是指向底层的数组array的数据结构。

map

map是一种存放无序键值对的集合。map可以通过key来快速检索数据,key类似于索引,指向数据的值。可以像迭代数组和切片那样迭代它,不过无法决定map的返回顺序,因为map是用hash表来实现的。

声明和初始化

//声明变量,默认map是nil
var m map[KeyType] ValueType

//使用make声明并初始化map
m := make(map[KeyType]ValueType)

// 初始化 + 赋值一体化
m := map[string]string{
    "a": "aa",
    "b": "bb",
}
  • slice、function和包含slice的struct类型不能作为map的KeyType。
  • ValueType可以是任意类型,甚至是另一个map。
  • 此处如果不初始化map,会创建一个nil map,往nil map中存储值会引起程序panic。

map使用

delete()函数

delete()函数用于删除集合的元素,参数为map和其对应的key。删除一个在map中不存在的key函数不会返回错误。具体使用如下:

m := map[string]int {
    "xiaoming": 14,
    "zhangqiang": 25,
    "wangxiaofei": 21,
}
delete(m, "xiaoming")

查找键值是否存在

m := map[string]int {
    "xiaoming": 14,
    "zhangqiang": 25,
    "wangxiaofei": 21,
}
if v, ok := m["xiaoming"]; ok {
  fmt.Println(v)
} else {
  fmt.Println("key not found")
}

遍历map

m := map[string]int {
    "xiaoming": 14,
    "zhangqiang": 25,
    "wangxiaofei": 21,
}
for i, v := range m {
  fmt.Printf("index:%s, value:%d", i, v)
}

特点总结:

  • map是go语言的内置引用类型,所以多个map指向同一个底层的情况下,一个值发生变化,全部发生变。
  • map是无序的,每次迭代的顺序都是不确定的。
  • map只有len没有cap。
  • map不是线程安全的,在多个go routine中使用的时候需要加锁。

参考资料

猜你喜欢

转载自blog.csdn.net/phantom_111/article/details/79466920