当前位置: 首页 > article >正文

Golang学习历程【第五篇 复合数据类型:数组切片】

Golang学习历程【第五篇 复合数据类型:数组&切片】

  • 1. 数组(Array)
    • 1.1 数组的定义
    • 1.2 初始化数组
    • 1.3 数据的循环遍历
    • 1.4 多维数组
  • 2. 切片(Slice)
    • 2.1 切片声明、初始化
    • 2.2 基于数组创建切片
    • 2.2 切片的长度(len)和容量(cap)*
  • 3. nil值
  • 4. 值类型和引用数据类型
  • 5. 切片常用函数
    • 5.1 创建切片:make
    • 5.2 扩容切片:append
    • 5.3 复制切片【深克隆】:copy
    • 5.4 切片的删除
    • 5.5 sort排序
      • 5.5.1 升序排序
      • 5.5.2 降序排序
  • 6. 扩展技巧
    • 6.1 语法提示
    • 6.2 方法参数、含义使用探究

1. 数组(Array)

数组: 一系列固定长度同一类型数据的集合。数组为值类型

1.1 数组的定义

var 变量名 = [元素个数]<数据类型>
// 声明 + 初始化,此时可将[元素个数]替换为[...],表示初始化任意多个数据
var 变量名 = [元素个数]<数据类型>{}
变量名:= [元素个数]<数据类型>{}

示例:

// 数组的定义
var arr1 [4]int
// len获取数据长度
fmt.Printf("类型:%T; \t数组长度:%v; \t数据:%v\n", arr1, len(arr1), arr1)

结果:

类型:[4]int;   数组长度:4;    数据:[0 0 0 0]

1.2 初始化数组

// 数组的定义
var arr1 [4]int
// len获取数据长度
fmt.Printf("类型:%T; \t数组长度:%v; \t数据:%v\n", arr1, len(arr1), arr1)
/* 数组初始化 */
// 1.方式一
arr1[0] = 1
arr1[3] = 4
fmt.Printf("方式一: 类型:%T; \t数组长度:%v; \t数据:%v\n", arr1, len(arr1), arr1)
// 2. 方式二 var 变量名 = [元素个数]<数据类型>{}
var arr2 = [3]float64{1, 2, 4.6}
fmt.Printf("方式二: 类型:%T; \t数组长度:%v; \t数据:%v\n", arr2, len(arr2), arr2)
// 3. 方式三 变量名:= [元素个数]<数据类型>{}
arr3 := [3]string{"java", "Golang", "Python"}
fmt.Printf("方式三: 类型:%T; \t数组长度:%v; \t数据:%v\n", arr3, len(arr3), arr3)
// 4. 方式四 var 变量名 = [...]<数据类型>{} 或 变量名:= [...]<数据类型>{}
arr4 := [...]int{2, 4, 6, 7, 8}
fmt.Printf("方式四: 类型:%T; \t数组长度:%v; \t数据:%v\n", arr4, len(arr4), arr4)
// 5. 方式五 指定下标索引初始化索引
arr5 := [...]float64{0: 2, 2: 3.5, 5: 4.6, 7: 9}
fmt.Printf("方式五: 类型:%T; \t数组长度:%v; \t数据:%v\n", arr5, len(arr5), arr5)

结果:

类型:[4]int;   数组长度:4;    数据:[0 0 0 0]
方式一: 类型:[4]int;   数组长度:4;    数据:[1 0 0 4]
方式二: 类型:[3]float64;       数组长度:3;    数据:[1 2 4.6]
方式三: 类型:[3]string;        数组长度:3;    数据:[java Golang Python] 
方式四: 类型:[5]int;   数组长度:5;    数据:[2 4 6 7 8]
方式五: 类型:[8]float64;       数组长度:8;    数据:[2 0 3.5 0 0 4.6 0 9]

1.3 数据的循环遍历

/* 数组的循环遍历 */
arr6 := [3]string{"java", "Golang", "Python"}
// 1. 使用fori循环
fmt.Printf("fori循环 ")
for i := 0; i < len(arr6); i++ {
	fmt.Printf("下标%v: 值:%v; \t", i, arr6[i])
}
fmt.Println()
// 2. 使用for range
fmt.Printf("for range循环 ")
for index, value := range arr6 {
	fmt.Printf("下标%v: 值:%v; \t", index, value)
}

结果:

fori循环 下标0: 值:java;       下标1: 值:Golang;      下标2: 值:Python;
for range循环 下标0: 值:java;  下标1: 值:Golang;      下标2: 值:Python;

1.4 多维数组

// 2维数组为例 var 变量名 = [行个数][列个数]数据类型{{}}
var arr7 = [3][3]int{
	{1, 2, 3}, // 每一行数据
	{4, 5, 6},
	{7, 8, 9},
}

fmt.Printf("类型:%T; \t数组长度:%v; \t数据:%v\n", arr7, len(arr7), arr7)
// 可以忽略行的数据个数,列的数据个数不允许忽略
var arr8 = [...][2]string{
	{"a", "b"},
	{"c", "d"},
}
fmt.Printf("类型:%T; \t数组长度:%v; \t数据:%v\n", arr8, len(arr8), arr8)

// 二维数组循环
for i := 0; i < len(arr7); i++ {
	for j := 0; j < len(arr7[i]); j++ {
		fmt.Printf("%v行%v列: 值:%v; \t", i+1, j+1, arr7[i][j])
	}
	fmt.Println()
}
for row, rowValue := range arr8 {
	for col, value := range rowValue {
		fmt.Printf("%v行%v列: 值:%v; \t", row+1, col+1, value)
	}
	fmt.Println()
}

结果:

类型:[3][3]int;        数组长度:3;    数据:[[1 2 3] [4 5 6] [7 8 9]]
类型:[2][2]string;     数组长度:2;    数据:[[a b] [c d]]
11: 值:1;  12: 值:2;  13: 值:3;
21: 值:4;  22: 值:5;  23: 值:6;
31: 值:7;  32: 值:8;  33: 值:9;
11: 值:a;  12: 值:b;
21: 值:c;  22: 值:d;

2. 切片(Slice)

切片:基于数组实现的一层封装,可变长度的序列,可自动扩容切片为引用类型

2.1 切片声明、初始化

var 变量名 = []<数据类型>
// 声明 + 初始化
var 变量名 = []<数据类型>{}
变量名:= []<数据类型>{}

示例:

// 切片的定义
var arr1 []int
// len获取数据长度
fmt.Printf("类型:%T; \t切片长度:%v; \t数据:%v\n", arr1, len(arr1), arr1)
/* 切片初始化 */
// 1. 方式一 var 变量名 = []<数据类型>{}
var arr2 = []float64{1, 2, 4.6}
fmt.Printf("方式一: 类型:%T; \t切片长度:%v; \t数据:%v\n", arr2, len(arr2), arr2)
// 2. 方式二 变量名:= []<数据类型>{}
arr3 := []string{"java", "Golang", "Python"}
fmt.Printf("方式二: 类型:%T; \t切片长度:%v; \t数据:%v\n", arr3, len(arr3), arr3)
// 3. 方式三 var 变量名 = []<数据类型>{} 或 变量名:= []<数据类型>{}
arr4 := []int{2, 4, 6, 7, 8}
fmt.Printf("方式三: 类型:%T; \t切片长度:%v; \t数据:%v\n", arr4, len(arr4), arr4)
// 4. 方式四 指定下标索引初始化索引
arr5 := []float64{0: 2, 2: 3.5, 5: 4.6, 7: 9}
fmt.Printf("方式四: 类型:%T; \t切片长度:%v; \t数据:%v\n", arr5, len(arr5), arr5)
// 5. 切片的循环和数组一致,这里不例举

结果:

类型:[]int;    切片长度:0;    数据:[]
方式一: 类型:[]float64;        切片长度:3;    数据:[1 2 4.6]
方式二: 类型:[]string;         切片长度:3;    数据:[java Golang Python] 
方式三: 类型:[]int;    切片长度:5;    数据:[2 4 6 7 8]
方式四: 类型:[]float64;        切片长度:8;    数据:[2 0 3.5 0 0 4.6 0 9]

2.2 基于数组创建切片

示例:

// 基于数组定义切片
var arr1 = [5]int{10, 29, 49, 58, 32}
fmt.Printf("类型:%T; \t长度:%v; \t数据:%v\n", arr1, len(arr1), arr1)
// 1. 切片获取,arr1[:]获取arr1中所有的数据
s1 := arr1[:]
// 切片数据类型为[]int,数组数据类型为[5]int
fmt.Printf("获取所有数据--类型:%T; \t长度:%v; \t数据:%v\n", s1, len(s1), s1)
// 2. 切片获取,arr1[2:]获取arr1中从下标为2开始之后所有的数据【包含下标2】
s2 := arr1[2:]
fmt.Printf("获取下标为2开始之后所有的数据--类型:%T; \t长度:%v; \t数据:%v\n", s1, len(s2), s2)
// 3. 切片获取,arr1[:2]获取arr1中从下标为2之前所有的数据【不包含下标2】
s3 := arr1[:2]
fmt.Printf("获取下标为2之前所有的数据--类型:%T; \t长度:%v; \t数据:%v\n", s3, len(s3), s3)

结果:

类型:[5]int;   长度:5;        数据:[10 29 49 58 32]
获取所有数据--类型:[]int;      长度:5;        数据:[10 29 49 58 32]
获取下标为2开始之后所有的数据--类型:[]int;     长度:3;        数据:[49 58 32]
获取下标为2之前所有的数据--类型:[]int;         长度:2;        数据:[10 29] 

总结:数据的拆分:arr[start:end] 中,含义为:获取arr对应下标区间[start,end)的值,start,end可省略,表示其前或后的所有值。

2.2 切片的长度(len)和容量(cap)*

切片拥有自己的长度和容量:
长度:切片的长度是切片所包含的元素个数。用**len()函数获取
容量:切片的容量从他第一个元素开始,到底层数组元素末尾的个数。用
cap()**函数获取

a := []int{2, 3, 4, 5, 6, 7}
fmt.Printf("类型:%T, 长度:%v, 容量:%v, 数据:%v\n", a, len(a), cap(a), a)
b := a[3:]
fmt.Printf("类型:%T, 长度:%v, 容量:%v, 数据:%v\n", b, len(b), cap(b), b)
c := a[:3]
fmt.Printf("类型:%T, 长度:%v, 容量:%v, 数据:%v\n", c, len(c), cap(c), c)

结果:

类型:[]int, 长度:6, 容量:6, 数据:[2 3 4 5 6 7]
类型:[]int, 长度:3, 容量:3, 数据:[5 6 7]
类型:[]int, 长度:3, 容量:6, 数据:[2 3 4]

在这里插入图片描述

3. nil值

nil是一个预先声明的标识符,表示指针、通道、函数、接口、集合或切片类型的零值。

数据类型声明默认值
bool
int,float0
string""
指针(pointers)nil
数组(array)基本类型默认值的数组
切片(slices)nil
集合(maps)nil
通道(channels)nil
函数(function)nil
// 数组默认值
var arr [3]int
fmt.Println(arr)
// 切片默认值
var slices1 []int
var slices2 = []int{1}
fmt.Println(slices1, slices1 == nil, slices2 == nil)

结果:

[0 0 0]
[] true false

4. 值类型和引用数据类型

值类型: 值类型赋值的两个变量为独立个体,A变化不会引起B的同步更新
引用数据类型:引用数据类型赋值的两个变量为引用同一个变量,A变化会引起B的变化。实际上是因为指向同一片内存空间。典型的示例即:切片
示例:

a1 := [...]int{2, 3, 4, 5}           // 数组 值复制
a2 := []int{2, 3, 4, 5}              // 切片 引用赋值
b1 := a1                             // 赋值给b1
b2 := a2                             // 赋值给b2
b1[0] = 6                            // 同样修改第一个元素值为6
b2[0] = 6                            // 同样修改第一个元素值为6
fmt.Printf("a1=%v,b1=%v \n", a1, b1) // 值类型赋值:b1的修改不会影响a1
fmt.Printf("a2=%v,b2=%v \n", a2, b2) // 引用类型赋值:b2的修改影响了a2

结果:

a1=[2 3 4 5],b1=[6 3 4 5] 
a2=[6 3 4 5],b2=[6 3 4 5] 

5. 切片常用函数

5.1 创建切片:make

make创建切片,make([]int, 10, 11) 分配一个底层数组大小为10,返回长度为11、容量为10的切片int类型切片

var slice1 = make([]int, 10, 11)
slice1[2] = 6
slice1[9] = 20
fmt.Printf("类型:%T, 长度:%v, 容量:%v, 数据:%v\n", slice1, len(slice1), cap(slice1), slice1)
/* 	结果:
类型:[]int, 长度:10, 容量:11, 数据:[0 0 6 0 0 0 0 0 0 20]
*/

5.2 扩容切片:append

切片扩容: append(slice, elem1, elem2)或者append(slice, anotherSlice...),slice表示需要扩容的切片,elem*表示添加的元素,anotherSlice表示其他切片

// 切片的扩容不能通过slice[2]下标越界方式,会报错下标越界:index out of range [2] with length 0
var slice2 = make([]int, 0, 0)
// 切片中追加一个元素,并返回最终元素
slice2 = append(slice2, 12, 14, 24)
fmt.Printf("类型:%T, 长度:%v, 容量:%v, 数据:%v\n", slice2, len(slice2), cap(slice2), slice2)
slice3 := []int{3, 4, 5}
// 切片的合并,slice3...代表slice3中所有的元素列举
var slice4 = append(slice2, slice3...)
fmt.Printf("类型:%T, 长度:%v, 容量:%v, 数据:%v\n", slice2, len(slice4), cap(slice4), slice4)
/* 结果:
类型:[]int, 长度:3, 容量:3, 数据:[12 14 24]
类型:[]int, 长度:6, 容量:6, 数据:[12 14 24 3 4 5]
 */

5.3 复制切片【深克隆】:copy

深克隆:指的是克隆前后的对象为两个独立的个体,后续修改变更互不影响
浅克隆:指的是克隆前后的对象为同一个引用类型,后续修改A同样影响B的值
copy(dst, src []Type),dst是destination,表示目的变量,src是source,表示对象源,即将src复制给dst

// 切片的扩容不能通过slice[2]下标越界方式,会报错下标越界:index out of range [2] with length 0
var slice2 = make([]int, 0, 0)
// 切片中追加一个元素,并返回最终元素
slice2 = append(slice2, 12, 14, 24)
fmt.Printf("类型:%T, 长度:%v, 容量:%v, 数据:%v\n", slice2, len(slice2), cap(slice2), slice2)
slice3 := []int{3, 4, 5}
// 切片的合并,slice3...代表slice3中所有的元素列举
var slice4 = append(slice2, slice3...)
fmt.Printf("类型:%T, 长度:%v, 容量:%v, 数据:%v\n", slice2, len(slice4), cap(slice4), slice4)
// 切片的复制深克隆
slice4Copy := make([]int, len(slice4))
copy(slice4Copy, slice4)
slice4Copy[0] = 6666
fmt.Println(slice4, slice4Copy)
/* 结果:
类型:[]int, 长度:3, 容量:3, 数据:[12 14 24]
类型:[]int, 长度:6, 容量:6, 数据:[12 14 24 3 4 5]
[12 14 24 3 4 5] [6666 14 24 3 4 5]
 */

5.4 切片的删除

Go语言中没有内置删除切片方法,可以使用append方法,与切片再切片结合实现

// 切片的删除
s1 := []int{1, 2, 3, 4, 5, 6}
// 删除元素的索引下标
delIndx := 3
// 通过切片append方法,与切片再切片结合实现,即截取[0,3)和[4,5]的切片数据再合并达到删除效果
s1 = append(s1[:delIndx], s1[delIndx+1:]...)
fmt.Println(s1)
/* 结果:
[1 2 3 5 6]
 */

5.5 sort排序

5.5.1 升序排序

使用sort.Ints、sort.Float64s、sort.Strings进行排序

intList := []int{3, 4, 32, 32, 423, 12}
float64List := []float64{3.13, 4.2, 5.3, 1.1}
stringList := []string{"D", "S", "A", "C"}
// 升序排序
sort.Ints(intList)
sort.Float64s(float64List)
sort.Strings(stringList)
fmt.Println(intList)
fmt.Println(float64List)
fmt.Println(stringList)
/* 结果:
[3 4 12 32 32 423]
[1.1 3.13 4.2 5.3]
[A C D S]
 */

5.5.2 降序排序

结合sort.XXXSlice、sort.Reverse和sort.Sort实现

intList := []int{3, 4, 32, 32, 423, 12}
float64List := []float64{3.13, 4.2, 5.3, 1.1}
stringList := []string{"D", "S", "A", "C"}
/*
	降序排序
		1. sort.IntSlice(intList)表示对intList转成interface,简单理解为将切片转为排序器接口,返回结果类型:data sort.Interface
		2. sort.Reverse(data sort.Interface)表示翻转切片,返回结果类型:data sort.Interface
		3. sort.Sort(data sort.Interface) 表示将结果排序返回数据
	默认当做固定写法:sort.Sort(sort.Reverse(sort.XXXSlice(intList)))
	另外也可以自定义排序算法实现降序排序
*/
sort.Sort(sort.Reverse(sort.IntSlice(intList)))
sort.Sort(sort.Reverse(sort.Float64Slice(float64List)))
sort.Sort(sort.Reverse(sort.StringSlice(stringList)))
fmt.Println(intList)
fmt.Println(float64List)
fmt.Println(stringList)
/* 结果: 
[423 32 32 12 4 3]
[5.3 4.2 3.13 1.1]
[S D C A]
 */

6. 扩展技巧

6.1 语法提示

对一个变量输入“.”符号时,编译器自动提示语法命令,后缀携带!的表示为功能快捷提示,并生成对应的半成品代码

在这里插入图片描述
截图中提示语功能

功能提示语句含义
append!切片追加数据
copy!copy克隆切片
for!fori循环
forr!for range循环
ifnotnil!if not nil 条件判断
last!等价于a[len(a -1)]获取最后一个元素
len!等价于len(a)获取长度
print!打印变量
range!等价于forr!
reverse!翻转切片
sort!自定定排序
var!将a赋值于新的变量

6.2 方法参数、含义使用探究

  1. 鼠标移动至方法名1s以上,显示方法名参数、返回值,含义,描述详情等信息

在这里插入图片描述

  1. 用ctrl按键+鼠标左键,点击方法名,即可进入方法名参数、返回值,含义,描述详情等信息,如果不懂英文,可以通过翻译工具认识逐步了解学习
    在这里插入图片描述

上一篇:Golang学习历程【第四篇 运算符&流程控制】
下一篇:Golang学习历程【第六篇 复合数据类型:map】 待续中。。。


http://www.kler.cn/a/463058.html

相关文章:

  • Uncaught ReferenceError: __VUE_HMR_RUNTIME__ is not defined
  • Redis(二)value 的五种常见数据类型简述
  • 《计算机网络A》单选题-复习题库
  • 每日一学——监控工具(Grafana)
  • TT100K数据集, YOLO格式, COCO格式
  • 【GO基础学习】gin的使用
  • ShardingSphere-Proxy分表场景测试案例
  • CPT203 Software Engineering 软件工程 Pt.4 软件设计(中英双语)
  • Spring 核心技术解析【纯干货版】- II:Spring 基础模块 Spring-Beans 模块精讲
  • pyside6总结
  • 网络编程原理:回显服务器与客户端通信交互功能
  • Day20:逻辑运算
  • 30.Marshal.AllocHGlobal C#例子
  • 递归算法.
  • AI对接之JSON Output
  • 使用连字符容易出错,尽量使用驼峰式的
  • java 上传txt json等类型文件解析后返回给前端
  • OpenCV-Python实战(9)——滤波降噪
  • C++“STL之String”
  • 说说缓存使用的具体场景都有哪些?缓存和数据库一致性问题该如何解决?缓存使用常见问题有哪些?
  • 融合表面信息和等变扩散的分子对接模型 SurfDock - 评测
  • Git的使用流程(详细教程)
  • NFT Insider #162:Cool Cats和Doodles或将推出代币
  • 线性表的三种常见查找算法(顺序查找、折半查找、分块查找)及算法分析
  • 无人机巡检在光伏电站中的应用优势
  • HarmonyOS NEXT版本Stage应用开发模型介绍(附视频讲解)