数组

var 数组名[数组大小]数据类型 var a [5]int

4种初始化方式

1
2
3
4
var numsArrays01 [3]int = [3]int {1,2,3}
var numsArrays02 = [3]int {1,2,3}
var numsArrays03 = [...]int {1,2,3}
var numsArrays04 = [3]string {1:"1",2:"2",0:"3"}

for-range遍历

1
2
3
4
5
6
func traverse(){
var numsArrays03 = [...]int {1,2,3}
for index, value := range numsArrays03 {
fmt.Println(index,value)
}
}

第一个返回值index是数组的下标第,二个value是该下标位置的值。
他们都是仅在 for循环内部可见的局部变量。
遍历数组元素的时候,如果不想使用下标index,可以直接把下标index标为下划线。
index和value的名称不是固定的.可以z自行指定。

注意

  1. var arr []int是一个slice切片
  2. 数组创建之后有默认值
  3. Go的数组属值类型,在默认情况下是值传递,因此会进行值拷贝。数组间不会相互影响如想在其它函数中,去修改原来的数组,可以使用引用传递(指针方式)
  4. 长度是数组的一部分,在传递函数参数时,需要考虑数组的长度

案例

1
2
3
4
5
6
7
8
9
10
11
12
13
//要求:随机生成五个数,并将其反转打印
//1.随机生成五个数, rand.Intn()函数
//2.当我们得到随机数后,就放到一个数组int数组
//3.反转打印
func randArr(){
var intArr [5] int
//需要加入随机数种子
rand.Seed(time.Now().UnixNano())
for i := 0 ;i < len(intArr); i++ {
intArr[i] = rand.Intn(100) // 0<=x<100
}
fmt.Println(intArr)
}

切片

  • 切片是数组的一个引用,因此切片是引用类型,在进行传递时,遵守引用传递的机制。
  • 切片的使用和数组类似,遍历切片、访问切片的元素和求切片长度len(slice)都一样。
  • 切片的长度是可以变化的,因此切片是一个可以动态变化数组
  • 切片定义的基本语法:
    var变量名[类型]比如: var a []int
1
2
3
4
5
6
7
func length(){
var intArr [5]int = [...]int{1,22,3,33,4}

slice := intArr[1:3]
fmt.Println(len(slice)) //长度
fmt.Println(cap(slice)) //容量 ,不定
}

内存布局

image-20220221232718199

  1. slice的确是一个引用类型,容量是动态变化的

  2. slice从底层来说,其实就是一个数据结构(struct结构体)

    1
    2
    3
    4
    5
    type slice struct {
    ptr *[2]int
    len int
    cap int
    )

使用方式

  1. 定义一个切片,然后让切片去引用一个已经创建好的数组。

  2. 第二种方式:通过make来创建切片.
    基本语法: var切片名[]type = make([], len,[cap])
    参数说明: type:就是数据类型len :大小cap:指定切片容量

    1
    var slice []float= make([]float64, 5, 10)
  3. 定义一个切片,直接就指定具体数组,使用原理类似make的方式。

    1
    var slice []sting = []string{"tom","jack","mary"}

方式一和方式2的区别:

方式1是直接引用数组,这个数组是事先存在的,程序员是可见的。
方式2是通过make来创建切片,make也会创建一个数组,是由切片在底层进行维护,程序员是看不见的。

切片和数组的变量方式相同

注意

  1. 切片初始化时var slice = arr[startlndex:endIndex]
    说明:从arr数组下标为startIndex,取到下标为endIndex的元素(不含arr[endIndex])
    切片初始化时,仍然不能越界。范围在[O-len(arr)]之间,但是可以动态增长.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    var slice = arr[0:end]
    //可以简写
    var slice = arr[:end]

    var slice = arr[start:len(arr)]
    //可以简写:
    var slice = arr[start:]

    var slice = arr[0:len(arr)]
    //可以简写:
    var slice = arr[:]
  1. cap是一个内置函数,用于统计切片的容量,即最大可以存放多少个元素。

  2. 切片定义完后,还不能使用,因为本身是一个空的,需要让其引用到一个数组,或者make一个空间供切片来使用

  3. 切片可以继续切片

  4. 使用append内置函数,可以对切片进行动态追加

    切片append操作的底层原理分析:

    1. 切片append操作的本质就是对数组扩容
    2. go底层会创建一下新的数组newArr(安装扩容后大小)
    3. 将slice原来包含的元素拷贝到新的数组newArr

    4) slice重新引用到newArr
    5) 注意newArr是在底层来维护的,程序员不可见.

  5. 使用内置函数copy完成拷贝

    1
    copy(slice,a) //把a拷贝到slice

string和slice

string底层是一个byte数组,因此string也可以进行切片处理

1
2
str := "helloworld"
slice := str[6:]

string是不可变的,也就说不能通过str[0]= 2方式来修改字符串

如果需要修改字符串,可以先将string -> []byte/或者[]rune ->修改→重写转成string.

1
2
3
4
5
6
7
8
arr1 :=[ ]byte(str)
arr1[e]= 'z'
str = string(arr1)

//中文
arr1 :=[ ]rune(str)
arr1[e]= '北'
str = string(arr1)

二维数组

1
2
var arr [2][3]int[][]
var arr [2][3]int

map

var map变量名 map[keytype]valuetype

1
2
3
4
5
6
7
8
9
10
func createMap(){
var a map[string]string
a = make(map[string]string, 10)

b := make(map[string]string)

c := map[string][string]{
"1":"1",
}
}
  • map在使用前一定要make
  • map的key是不能重复,如果重复了,则以最后这个key-value为准
  • map的 value是可以相同的.
  • map的 key-value是无序

操作

  • 增加和更新: map[“key”]=value

  • 删除 delete(map.”key),

    全部删除可以直接创建一个新的map

  • 查找

    1
    2
    3
    4
    val,ok := a["1"]
    if ok {
    fmt.println(val)
    }
  • 遍历

    1
    2
    3
    4
    5
    6
    7
    8
    9
    func tarverse(){
    a := make(map[string]string)
    a["1"] = "1"
    a["2"] = "2"
    a["3"] = "3"
    for k,v := range a {
    fmt.Println(k,v)
    }
    }

map排序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
func sortMap(){
a := make(map[string]string)
a["1"] = "1"
a["2"] = "2"
a["4"] = "4"
a["3"] = "3"
var keys []string
for k,_ := range a{
keys = append(keys, k)
}
sort.Strings(keys)
for _ , k := range keys {
fmt.Println(a[k])
}
}

使用切片辅助排序

细节

  • map是引用类型,遵守引用类型传递的机制,在一个函数接收map,修改后,会直接修改原来的map
  • map的容量达到后,再想map增加元素,会自动扩容,并不会发生panic,也就是说map能动态的增长键值对(key-value)
  • map的value也经常使用struct类型,更适合管理复杂的数据