4.数组、切片、map

数组

数组的定义

var 变量名称 [长度]数据类型
// 其中长度需要是确定的量,不可以是变量或表达式

数组初始化

  1. 定义时使用
var citys = [4]string{"北京","上海","广州","深圳"}
  1. 编译器推导数组的长度
var boolArray = [...]bool{false, true}
  1. 使用索引值的方式
var langArray = [...]string{1:"Golang", 3:"Python", 6:"Java"}
// 除了下标为1,3,6的位置有值外,其他地方都是空串

数组的遍历

  1. 使用for循环
var citys = [4]string{"北京","上海","广州","深圳"}
for i:=0,i<len(citys);i++{
  fmt.Println(i)
  fmt.Println(citys[i])
}
  1. for range 遍历
for index, value := range citys{
  fmt.Println(index, value)
}

for _, value := range citys{
  fmt.Println(value)
}

多维数组

二维数组

其实就是数组里再嵌套一个数组

citys:=[3][2]string{
  {"北京","西安"},
  {"上海","杭州"},
  {"天津","广州"}
}
fmt.Println(citys[1][1])  // 杭州

遍历二维数组

for _,v1:=range citys{
  for _, v2 := range v1{
    fmt.Println(v2)
  }
}

数组是值类型,所以在走赋值操作的时候其实是都是值传递

package main

import "fmt"

func main() {
  x:=[2]int{1,2,3}
  fmt.Println(x) // [1,2]
  f1(x)
  fmt.Println(x) // [1,2]
  // 在调用函数的前后x的值没有变化,因为在传递的时候不是传递的地址(索引传递),所以函数内修改的值不会改变x本身的值
}

func f1(a[2]int){
  a[0] = 100
}

切片

拥有相同类型元素的可变长度的序列,是基于数组类型的一层封装

但切片和数组不同,切片是引用类型

切片在容量不够时会自动扩容,但是在定义切片的时候应提前想好切片的容量,尽量避免自动扩容,自动扩容会产生额外的内存消耗

定义

var a []string // 中括号内不需要加数字

var b []int{1,2,3} // 定义时初始化

// 基于数组得到切片
a:=[5]int{1,2,3,4,5}
b:=a[1:4] //[2,3,4]  左闭右开
c:=b[:] // c:=b[0:len(b)]的简写。对切片再次切片

// make函数构造切片
d:=make([]int, 5, 10) // 得到一个长度为5,容量为10的切片,容量不写时默认和长度一致
fmt.Println(len(d)) // 长度为5
fmt.Println(cap(d)) // 容量为10

切片不能直接进行比较,不可以使用==操作符来判断两个切片是否含有全部相等的元素,切片唯一合法的比较操作是和nil比较

一个nil值的切片并没有底层数组,其长度和容量都是0,但一个长度和容量都是0的切片不一定是nil

var s1 []int         //len(s1)=0;cap(s1)=0;s1==nil
s2 := []int{}        //len(s2)=0;cap(s2)=0;s2!=nil
s3 := make([]int, 0) //len(s3)=0;cap(s3)=0;s3!=nil
// 所以无法通过是否==nil来判断一个切片是否为空,应该判断len()==0

切片的赋值拷贝

a:=make([]int, 3) // [0,0,0]
b := a // 这时候a和b是共用一个底层数组的
b[0] = 100 // a:[100,0,0] b:[100,0,0]

切片的遍历

// 与数组的遍历相同
a:[]int{1,2,3,4,5}
for i:=0;i<len(a);i++{
  fmt.Println(a[i])
}
for i,v:=range a{
  fmt.Println(i,v)
}

append方式添加元素

var a[]int // 此时并没有申请内存,所以无法通过下标的方式赋值
// a[0] = 100 会报错,切片需要初始化之后才能使用
a = append(a, 10) // 在原有数组容量不够的时候,会自动扩容,所以append函数必须要有一个变量来接受,因为它可能返回原来的数组,也可能返回一个新的数组
// 一次追加多个元素
var a[]int
a = append(a, 1,2,3,4,5)

// 切片中追加切片
b := []int{1,2,3,4}
a = append(a, b...)

使用copy()函数赋值切片

a:=[]int{1,2,3,4,5}
b = make([]int, 5, 5)
copy(b,a)
fmt.Println(a, b) // 此时a和b看起来是一样的,但他们并没有指向同一个内存地址
a[0] = 100
fmt.Println(a, b) // a:[100,2,3,4,5]  b:[1,2,3,4,5]

切片的删除

// 借助append()实现删除操作
a:=[]string{"北京","上海","深圳"}
a = append(a[0:2], a[3:]...)
// append(a[:index], a[index+1:]...)

切片的排序

a:=[...]int{3,4,6,2,1}
sort.Ints(a[:])  // 因为切片的是指向数组的,所以对切片进行排序就是对原来的数组进行排序
fmt.Println(a)

map

go语言中,map也是一种引用类型,不初始化的时候无法直接使用

map是无序的,键值对的顺序和添加的顺序是无关的

map的声明

var a map[string]int
// 和切片一样,只声明不初始化的map,默认值是nil,无法直接使用

初始化

a = make(map[string]int, 8)

添加键值对

a["high"] = 12
a["width"] = 10
fmt.Printf("a:%#v\n", a)

声明的同时完成初始化

b:=map[int]bool{
  1:true,
  2:false,
}

判断某个键是否存在

var scoreMap = make(map[string]int,8)
scoreMap["张三"]=100
scoreMap["李四"]=200
v,ok := scoreMap["王五"]
if ok{
  fmt.Println("王五在map中")  // value=100
}else{
  fmt.Println("王五不在map中")// value=0
}

map的遍历

var scoreMap = make(map[string]int,8)
scoreMap["张三"]=100
scoreMap["李四"]=200

for k,v := range scoreMap{
  fmt.Println(k,v)
}

// 值遍历map中的key
for k := range scoreMap{
  fmt.Println(k)
}
// 只遍历map中的value
for _,v:=range scoreMap{
  fmt.Println(v)
}

删除map中的键值对

var scoreMap = make(map[string]int,8)
scoreMap["张三"]=100
scoreMap["李四"]=200

delete(scoreMap, "张三")  // 删除的值不在map中时,也不会报错
fmt.Println(scoreMap)

map排序

package main

import (
	"fmt"
	"math/rand"
	"sort"
)

func main() {
	var scoreMap = make(map[string]int, 100)

	for i := 0; i < 50; i++ {
		key := fmt.Sprintf("stu%02d", i)
		value := rand.Intn(100)
		scoreMap[key] = value
	}
	// 1.先取出所有的key放到切片中
	keys := make([]string, 0, 100)
	for k := range scoreMap {
		keys = append(keys, k)
	}
	// 2.对key做排序
	sort.Strings(keys)
	// 3.按照排序后的key对scoreMap排序
	for _, v := range keys {
		fmt.Println(v, scoreMap[v])
	}
}

复杂类型数据

元素为map的切片

var mapSlice = make([]map[string]int, 8) //此时只是完成了切片的初始化,还无法直接使用
mapSlice[0] = make(map[string]int, 2)
mapSlice[0]["张三"] = 10
fmt.Println(mapSlice)

值是切片的map

var sliceMap = make(map[string][]int, 8) // 此时只是完成了map的初始化,无法直接使用

v, ok := sliceMap["中国"]
if ok {
	fmt.Println(v)
	fmt.Println(sliceMap["中国"])
} else {
		sliceMap["中国"] = make([]int, 8) // 完成对切片的初始化
		sliceMap["中国"][0] = 100
		sliceMap["中国"][1] = 200
}

	// 遍历sliceMap
for k, v := range sliceMap {
		fmt.Println(k, v)
}

统计一个字符串中每个单词出现的次数

package main

import (
	"fmt"
	"strings"
)

func main() {
	var s string = "how do you do"
	var c map[string]int = make(map[string]int, 10)
	words := strings.Split(s, " ")
	for _, v := range words {
		_, ok := c[v]
		if ok {
			c[v] += 1
		} else {
			c[v] = 1
		}
	}
	fmt.Println(c)
}
// 也可以利用不存在的键返回对应零值的特性
func main() {
	var s string = "how do you do"
	var c map[string]int = make(map[string]int, 10)
	words := strings.Split(s, " ")
	for _, v := range words {
		c[v] += 1
	}
	fmt.Println(c)
}

posted @ 2025-06-12 18:40  L大官  阅读(5)  评论(0)    收藏  举报