Go后端开发 -- 数组 && slice && map && range

Go后端开发 -- 数组 && slice && map && range

文章目录


一、数组

1.数组的声明和初始化

go中的数组是固定长度的;
声明数组

  • Go 语言数组声明需要指定元素类型及元素个数,语法格式如下:
go 复制代码
var variable_name [SIZE] variable_type

例如:

go 复制代码
var balance [10] float32

初始化数组

  • 初始化数组中 {} 中的元素个数不能大于 \[\] 中的数字。
go 复制代码
var balance = [5]float32{1000.0, 2.0, 3.4, 7.0, 50.0}
//也可以省略var
balance2 = [5]float32{1000.0, 2.0, 3.4, 7.0, 50.0}
  • 如果忽略 \[\] 中的数字不设置数组大小,Go 语言会根据元素的个数来设置数组的大小:
go 复制代码
 var balance = []float32{1000.0, 2.0, 3.4, 7.0, 50.0}
  • 以下实例读取了第五个元素。数组元素可以通过索引(位置)来读取(或者修改),索引从0开始,第一个元素索引为 0,第二个索引为 1,以此类推。
go 复制代码
 balance[4] = 50.0

实例:

go 复制代码
package array_go

import "fmt"

func Array() {
	var arr1 [10]int
	arr2 := []int{1, 2, 3}

	fmt.Println(arr1[0])

	for i := 0; i < len(arr1); i++ {
		fmt.Println(arr2[i])
	}
}
  • 注意:数组中未初始化的元素默认为0

2.数组的传参

  • 数组传参的形参类型只能写成固定类型的数组,如myArr [10]int,数组的长度是固定的,不同长度的数组属于不同的类型;

实例

go 复制代码
package array_go

import "fmt"

func Array() {
	var arr1 [10]int

	printArr(arr1)
}

func printArr(myArr [10]int) {
	for i, num := range myArr {
		fmt.Println(i, num)
	}
}
  • 数组传参是值传递,传入函数的数组只是原数组的值拷贝,修改函数中的数组并不会影响原数组

二、slice切片

Go 语言切片是对数组的抽象。
Go 数组的长度不可改变 ,在特定场景中这样的集合就不太适用,Go中提供了一种灵活,功能强悍的内置类型切片("动态数组") ,与数组相比切片的长度是不固定的,可以追加元素,在追加时可能使切片的容量增大

  • 切片底层是有一个数组的,切片的变量名就是指向底层数组首地址的指针

1.slice的定义和初始化

定义切片:

  • 可以声明一个未指定大小的数组来定义切片:
    切片不需要说明长度
go 复制代码
var identifier []type
  • 或使用make()函数来创建切片,make函数可以为容器开辟空间
go 复制代码
var slice1 []type = make([]type, len)


也可以简写为


slice1 := make([]type, len)
  • 也可以指定容量,其中capacity为可选参数。
go 复制代码
make([]T, length, capacity)

这里 len 是数组的长度并且也是切片的初始长度。

实例:

go 复制代码
func Slice() {
	//切片定义
	var slice1 [] int
	var slice2 = make([]int, 5)
	slice3 := make([]int, 3, 10)
}

切片初始化

  • 直接初始化切片,\[\]表示是切片类型,{1,2,3}初始化值依次是1,2,3.其cap=len=3
go 复制代码
s :=[] int {1,2,3 }
  • 初始化切片s,是数组arr的引用
go 复制代码
s := arr[:]
  • 将arr中从下标startIndex到endIndex-1 下的元素创建为一个新的切片
go 复制代码
s := arr[startIndex:endIndex]
  • 缺省endIndex时将表示一直到arr的最后一个元素
go 复制代码
s := arr[startIndex:]
  • 缺省startIndex时将表示从arr的第一个元素开始
go 复制代码
s := arr[:endIndex]
  • 通过切片s初始化切片s1
go 复制代码
s1 := s[startIndex:endIndex]
  • 通过内置函数make()初始化切片s,\[\]int 标识为其元素类型为int的切片
go 复制代码
s :=make([]int,len,cap)

实例

go 复制代码
func Slice() {
	//切片初始化
	arr := [3]int{1, 2, 3}
	s1 := []int{4, 5, 6}
	s3 := arr[0:2]
	//s4 := arr[1:]
	//s5 := arr[:3]
	s6 := s1[1:]

	for i := 0; i < len(s3); i++ {
		fmt.Println(s3[i])
	}
	for i := 0; i < len(s6); i++ {
		fmt.Println(s6[i])
	}
}
  • 注意:[startIndex:endIndex]初始化的是startIndex到endIndex-1的元素;

2.len()和cap()函数

  • 切片是可索引的,并且可以由 len() 方法获取长度。
  • 切片提供了计算容量的方法 cap() 可以测量切片最长可以达到多少。

实例:

go 复制代码
package slice_go

import "fmt"

func Slice() {
	s1 := []int{4, 5, 6}

	fmt.Println("s1 len:", len(s1), "s1 cap:", cap(s1))
}

3.空切片

一个切片在未初始化之前默认为 nil,长度为 0
实例

go 复制代码
package slice_go

import "fmt"

func Slice() {
	var s1 []int

	fmt.Println("s1 len:", len(s1), "s1 cap:", cap(s1), "s1 = ", s1)

	if s1 == nil {
		fmt.Println("切片是空的")
	}
}

4.切片截取

可以通过设置下限及上限来设置截取切片[lower-bound:upper-bound]
实例

go 复制代码
package slice_go

import "fmt"

func Slice() {
	s1 := []int{1, 2, 3, 4, 5, 6, 7, 8, 9}

	//打印原始切片
	fmt.Println("s1 = ", s1)

	//打印子切片,从索引1(包含)到索引4(不包含)
	fmt.Println("s1[1:4]", s1[1:4])

	//默认下限为0
	fmt.Println("s1[:5]", s1[:5])

	//默认上限为len(s1)
	fmt.Println("s1[4:]", s1[4:])
}
  • 若切片和数组截取后直接赋值给其他切片,那么这两个切片指向的是同一个地址的数组,相当于执行的是浅拷贝

    如果更改任意切片中元素的值,则两个切片的值都会被改变
go 复制代码
package slice_go

import "fmt"

func Slice() {
	arr := [5]int{1, 2, 3}
	s := []int{4, 5, 6}

	s1 := arr[1:]
	s2 := s[1:]

	s1[0] = 100
	s2[0] = 200

	fmt.Println(arr)
	printSlice(s1)

	printSlice(s)
	printSlice(s2)
}

func printSlice(arr []int) {
	fmt.Println("len = ", len(arr), "cap = ", cap(arr), "numbers = ", arr)
}

5.append() 和 copy() 函数

如果想增加切片的容量,我们必须创建一个新的更大的切片并把原分片的内容都拷贝过来。

实例:

go 复制代码
package slice_go

import "fmt"

func Slice() {
	var numbers []int

	//允许追加空切片
	numbers = append(numbers, 0)
	fmt.Println("len = ", len(numbers), "cap = ", cap(numbers), "numbers = ", numbers)

	//向切片追加一个元素
	numbers = append(numbers, 1)
	fmt.Println("len = ", len(numbers), "cap = ", cap(numbers), "numbers = ", numbers)

	//同时添加多个元素
	numbers = append(numbers, 2, 3, 4)
	fmt.Println("len = ", len(numbers), "cap = ", cap(numbers), "numbers = ", numbers)

	//创建切片,是numbers的两倍容量
	numbers1 := make([]int, len(numbers), cap(numbers)*2)
	//拷贝numbers的数据到numbers1中
	copy(numbers1, numbers)
	fmt.Println("len = ", len(numbers1), "cap = ", cap(numbers1), "numbers = ", numbers1)
}
  • copy函数执行的是深拷贝,拷贝前后的切片指向的是不同的地址空间
  • 而且copy函数会覆盖slice中的原始数据

实例

go 复制代码
package slice_go

import "fmt"

func Slice() {
	//arr := [5]int{1, 2, 3}
	s1 := []int{4, 5, 6, 7, 8}

	//s1 := arr[1:]
	s2 := make([]int, 3)
	copy(s2, s1[2:5])
	s2[0] = 100

	printSlice(s1)
	printSlice(s2)
}

func printSlice(arr []int) {
	fmt.Println("len = ", len(arr), "cap = ", cap(arr), "numbers = ", arr)
}

6.slice的传参

  • 使用slice作为函数参数类型,就不会收到数组长度的限制;
go 复制代码
package slice_go

import "fmt"

func Slice() {
	arr1 := []int{1, 2, 3, 4}
	printSlice(arr1)
}

func printSlice(arr []int) {
	fmt.Println("len = ", len(arr), "cap = ", cap(arr), "numbers = ", arr)
}
  • slice在传参的过程中是引用传递(传递的指针),不是值传递,可以在函数中直接修改原slice;
go 复制代码
package slice_go

import "fmt"

func Slice() {
	arr1 := []int{1, 2, 3, 4}
	changeSlice(arr1)
}

func changeSlice(arr []int) {
	arr[2] = 10
	fmt.Println(arr)
}

三、map

Map 是一种无序的键值对的集合 。Map 最重要的一点是通过 key 来快速检索数据,key 类似于索引,指向数据的值

Map 是一种集合,所以我们可以像迭代数组和切片那样迭代它。不过,Map 是无序的,我们无法决定它的返回顺序,这是因为 Map 是使用 hash 表来实现的。

1.map的声明和定义

  • 可以使用内建函数 make ,也可以使用 map 关键字来定义 Map:
go 复制代码
/* 声明变量,默认 map 是 nil */
var map_variable map[key_data_type]value_data_type

/* 使用 make 函数 */
map_variable = make(map[key_data_type]value_data_type)

如果不初始化 map,那么就会创建一个 nil map。nil map 不能用来存放键值对

第一种声明

  • 先定义map,再用make函数开辟空间
go 复制代码
package map_go

import "fmt"

func Map() {
	var map1 map[string]string //此时的map是空的
	//在使用map前,需要先make,make的作用就是给map分配数据空间
	map1 = make(map[string]string, 10)
	map1["one"] = "php"
	map1["two"] = "golang"
	map1["three"] = "java"
	fmt.Println(map1)
}


第二种声明

  • 直接使用make函数声明和定义
go 复制代码
package map_go

import "fmt"

func Map() {
	map2 := make(map[string]string) // 此处可以不写map的大小,后面赋值的时候会自动扩容
	map2["one"] = "php"
	map2["two"] = "golang"
	map2["three"] = "java"
	fmt.Println(map2)
}


第三种声明

  • 直接在声明时赋值,每个键值对后都要加,
go 复制代码
package map_go

import "fmt"

func Map() {
	map3 := map[string]string{
		"one":   "php",
		"two":   "golang",
		"three": "java", // 每一个键值对后面都需要加,
	}
	fmt.Println(map3)
}


实例:

go 复制代码
package map_go

import "fmt"

func Map() {
	language := make(map[string]map[string]string)
	language["php"] = make(map[string]string, 2)
	language["php"]["id"] = "1"
	language["php"]["desc"] = "php是世界上最美的语言"

	language["golang"] = make(map[string]string, 2)
	language["golang"]["id"] = "2"
	language["golang"]["desc"] = "golang抗并发非常good"
	language["golang"]["name"] = "golang"

	fmt.Println(language)
}

2.map的增删查改

  • 增、改都使用map_name[key_data]就可以实现;
  • 而删除需要使用delete函数delete(map_name, key_data)
  • 查的时候,使用val, key = mapname[key_data]可以得到map中该key_data对应的val_data,如果存在,val会被赋值val_datakey会被赋值true;如果不存在,key会被赋值false;(注意返回顺序,第一个返回值是val_data,第二个返回值是key是否存在)

实例

go 复制代码
package map_go

import "fmt"

func Map() {
	language := make(map[string]map[string]string)
	language["php"] = make(map[string]string, 2)
	language["php"]["id"] = "1"
	language["php"]["desc"] = "php是世界上最美的语言"

	language["golang"] = make(map[string]string, 2)
	language["golang"]["id"] = "2"
	language["golang"]["desc"] = "golang抗并发非常good"
	language["golang"]["name"] = "golang"

	fmt.Println(language)

	//增
	language["cpp"] = make(map[string]string)
	language["cpp"]["id"] = "3"
	fmt.Println(language)

	//删
	delete(language, "cpp")
	delete(language["php"], "desc")
	fmt.Println(language)

	//查
	val, key := language["golang"]
	if key {
		fmt.Println(key, val)
	} else {
		fmt.Println("no key")
	}

	//改
	language["golang"]["name"] = "GOLANG"
	fmt.Println(language)
}

3.map的传参

  • map的传参是引用传参
go 复制代码
package map_go

import "fmt"

func Map() {
	map1 := make(map[int]string)
	map1[1] = "cpp"
	map1[2] = "java"
	map1[3] = "golang"

	fmt.Println(map1)
	fmt.Println("-------------")
	changeMap(map1)
	fmt.Println(map1)
}

func changeMap(myMap map[int]string) {
	myMap[0] = "python"
}

四、Go 语言范围(Range)

Go 语言中 range 关键字用于for循环中迭代数组(array)、切片(slice)、通道(channel)或集合(map)的元素。在数组和切片中它返回元素的索引值,在集合中返回 key-value 对的 key 值。

对于映射,它返回下一个键值对的键。Range返回一个值或两个值。如果在Range表达式的左侧只使用了一个值,则该值是下表中的第一个值。

实例

go 复制代码
package range_go

import "fmt"

func Range() {
	arr1 := [5]int{1, 2, 3, 4}
	for i, num := range arr1 {
		fmt.Println(i, num)
	}

	slice1 := arr1[:3]
	for i, num := range slice1 {
		fmt.Println(i, num)
	}

	map1 := make(map[int]string)
	map1[0] = "xiaoming"
	map1[1] = "xiaogang"
	map1[2] = "xiangzhao"
	for key, value := range map1 {
		fmt.Println(key, value)
	}
}
  • 如果range返回的两个值中,不想访问某个值,可以使用_代替,表示匿名接受:
go 复制代码
package range_go

import "fmt"

func Range() {
	arr1 := [5]int{1, 2, 3, 4}

	for _, num := range arr1 {
		fmt.Println(num)
	}
}
相关推荐
红尘散仙1 天前
我把终端小说阅读器接上了 AI Agent:TRNovel 现在能用 skill 生成书源了
人工智能·后端·rust
卷毛的技术笔记1 天前
告别硬编码!Spring AI Alibaba 实现 AI Agent 智能工具调用(Tool Calling)
java·人工智能·后端·python·spring·ai编程
isyangli_blog1 天前
OpenDayLight (Carbon 版本) 启动与组件安装
开发语言·php
vb2008111 天前
FastAPI APIRouter
开发语言·python
Benszen1 天前
KVM虚拟化解决方案
开发语言·perl
会编程的土豆1 天前
Go 语言反射(Reflection)详解
开发语言·后端·golang
東雪木1 天前
多线程与并发编程 专属复习笔记
java·开发语言·笔记·java面试
喵个咪1 天前
GoWind Toolkit Go后端代码生成 完整全流程实战
后端·go·orm
杨充1 天前
1.3 浮点型数据设计灵魂
开发语言·python·算法
噜噜噜阿鲁~1 天前
python学习笔记 | 11.3、面向对象高级编程-多重继承
java·开发语言