go数组与切片【golang笔记】原创
原创一、数组
数组是相同类型的数据的集合。数组中包含的每个数据称为数组元素(element),这个类型可以是原来的类型的意思,比如。int、string依此类推,也可以是用户定义的类型。数组中包含的元素的数量称为数组的长度。在……里面Golang数组是固定长度的数据类型,数组的长度是该类型的一部分,也就是说。[5]int和[10]int是两种不同的类型。Golang数组的另一个特点是占用内存的连续性,即数组中的元素被分配到连续的内存地址,所以数组元素的索引非常快。
与该数组对应的类型为Slice(切片),Slice是一个动态的序列,可以增长和收缩,功能上更灵活,但想要理解。slice其工作原理需要了解数组,因此本节主要解释数组的用法。
数组定义
var 数组变量名 [元素数量] T
示例
// 数组的长度是类型的一部分。。
var arr1 [3]int
var arr2 [4]string
fmt.Printf("%T, %T
", arr1, arr2)
// 阵列的初始化 第一种方法
var arr3 [3]int
arr3[0] = 1
arr3[1] = 2
arr3[2] = 3
fmt.Println(arr3)
// 初始化数组的第二种方法
var arr4 = [4]int {10, 20, 30, 40}
fmt.Println(arr4)
// 第三种数组初始化方法自动推断数组的长度。
var arr5 = [...]int{1, 2}
fmt.Println(arr5)
// 初始化数组的第四种方法指定下标
a := [...]int{1:1, 3:5}
fmt.Println(a)
遍历数组
方法1
// 初始化数组的第四种方法指定下标
a := [...]int{1:1, 3:5}
for i := 0; i < len(a); i++ {
fmt.Print(a[i], " ")
}
方法2
// 初始化数组的第四种方法指定下标
a := [...]int{1:1, 3:5}
for _, value := range a {
fmt.Print(value, " ")
}
数组的值类型
数组是一种值类型,赋值和传输将赋值整个数组,因此更改副本的值不会更改其本身的值。
// 数组
var array1 = [...]int {1, 2, 3}
array2 := array1
array2[0] = 3
fmt.Println(array1, array2)
例如,在上面的代码中,在我们为数组赋值之后,当我们更改数组中的值时,我们会发现以下结果
[1 2 3] [3 2 3]
这说明,golang中的数组是值类型,而不是AND。java这同样属于参考数据类型。
切片定义(引用类型)
在golang在中,片的定义类似于数组的定义,但应该注意,片是一种引用数据类型,如下所示。
// 切片定义
var array3 = []int{1,2,3}
array4 := array3
array4[0] = 3
fmt.Println(array3, array4)
我们更改第一个切片元素,然后查看最终效果。
[3 2 3] [3 2 3]
二维数组
Go该语言支持多维数组。让我们以二维数组为例(数组嵌套在数组中):
var 数组变量名 [元素数量][元素数量] T
示例
// 二维数组
var array5 = [2][2]int{{1,2},{2,3}}
fmt.Println(array5)
数组遍历
二维数据集的遍历
// 二维数组
var array5 = [2][2]int{{1,2},{2,3}}
for i := 0; i < len(array5); i++ {
for j := 0; j < len(array5[0]); j++ {
fmt.Println(array5[i][j])
}
}
遍历方式2
for _, item := range array5 {
for _, item2 := range item {
fmt.Println(item2)
}
}
类型推导
此外,当我们创建数组时,我们也可以使用类型派生,但只能使用一个 …
// 二维数组(书写正确)
var array5 = [...][2]int{{1,2},{2,3}}
错误写法
// 二维数组
var array5 = [2][...]int{{1,2},{2,3}}
完整代码
package main
import "fmt"
func main() {
// 数组的长度是类型的一部分。。
var arr1 [3]int
var arr2 [4]string
fmt.Printf("%T, %T
", arr1, arr2)
// 阵列的初始化 第一种方法
var arr3 [3]int
arr3[0] = 1
arr3[1] = 2
arr3[2] = 3
fmt.Println(arr3)
// 数组的第二次初始化是非法的。
var arr4 = [4]int {10, 20, 30, 40}
fmt.Println(arr4)
// 第三种数组初始化方法自动推断数组的长度。
var arr5 = [...]int{1, 2}
fmt.Println(arr5)
// 初始化数组的第四种方法指定下标
a := [...]int{1:1, 3:5}
fmt.Println(a)
for i := 0; i < len(a); i++ {
fmt.Print(a[i], " ")
}
for _, value := range a {
fmt.Print(value, " ")
}
fmt.Println()
// 值类型 引用类型
// 基本数据类型和数组是值类型。
var aa = 10
bb := aa
aa = 20
fmt.Println(aa, bb)
// 数组
var array1 = [...]int {1, 2, 3}
array2 := array1
array2[0] = 3
fmt.Println(array1, array2)
// 切片定义
var array3 = []int{1,2,3}
array4 := array3
array4[0] = 3
fmt.Println(array3, array4)
// 二维数组
var array5 = [...][2]int{{1,2},{2,3}}
for i := 0; i < len(array5); i++ {
for j := 0; j < len(array5[0]); j++ {
fmt.Println(array5[i][j])
}
}
for _, item := range array5 {
for _, item2 := range item {
fmt.Println(item2)
}
}
}
二、切片
为什么要使用切片
切片(Slice是具有相同类型元素的可变长度序列。它是基于数组类型的封装层。
它非常灵活,支持自动扩展。
切片是一种引用类型,其内部结构包含地址、长度和容量。
声明切片类型的基本语法如下:
var name [] T
其中:
- name:表示变量名
- T:表示切片中的元素类型。
举例
// 声明一个切片,去掉长度是一个切片。
var slice = []int{1,2,3}
fmt.Println(slice)
关于nil的认识
当您声明一个变量但尚未赋值时,golang您的变量将自动分配一个默认的零值。这是每种类型的零值。
- bool:false
- numbers:0
- string:""
- pointers:nil
- slices:nil
- maps:nil
- channels:nil
- functions:nil
nil表示为空,即数组初始化默认为nil
var slice2 [] int
fmt.Println(slice2 == nil)
运行结果
true
切片的遍历
切片的遍历与数组的遍历相同。
var slice = []int{1,2,3}
for i := 0; i < len(slice); i++ {
fmt.Print(slice[i], " ")
}
基于数组定义切片
因为切片的底层是一个数组,所以我们可以基于该数组来定义切片。
// 基于数组定义切片
a := [5]int {55,56,57,58,59}
// 获取数组的所有值并返回一个切片。
b := a[:]
// 从数组中获取指定的切片。
c := a[1:4]
// 获取 下标3以前的数据(不包括3)
d := a[:3]
// 获取下标3后期数据(包括3)
e := a[3:]
运行结果
[55 56 57 58 59]
[55 56 57 58 59]
[56 57 58]
[55 56 57]
[58 59]
同样,我们不仅可以对数组进行切片,还可以对切片进行切片。
切片长度和容量
切片有自己的长度和容量,我们可以使用内置的len函数来计算长度,使用内置的cap()
函数以查找切片体积。
切片长度是它所包含的元素的数量。
片的容量是从其第一个元素到其底层数组元素末尾的数字。切片s的长度和容量len(s)和cap(s)来获得。
举例
// 长度和容量
s := []int {2,3,5,7,11,13}
fmt.Printf("长度%d 容量%d
", len(s), cap(s))
ss := s[2:]
fmt.Printf("长度%d 容量%d
", len(ss), cap(ss))
sss := s[2:4]
fmt.Printf("长度%d 容量%d
", len(sss), cap(sss))
运行结果
长度6 容量6
长度4 容量4
长度2 容量4
为什么最后一个容量不同,因为我们知道切片后sss = [5, 7] 所以切片长度是2,但一个是因为容量来自于。2的地位4
切片的性质
切片的性质就是对底层数组的封装,它包含了三个信息
- 指向基础数组的指针
- 切片长度(len)
- 切片体积(cap)
使用make函数构造切片
我们都基于数组创建切片。如果我们需要动态创建切片,则需要使用内置的make函数,格式如下:
make ([]T, size, cap)
其中:
- T:切片的元素类型。
- size:切片中的元素数
- cap:切片体积
举例:
// make()函数来创建切片
fmt.Println()
var slices = make([]int, 4, 8)
//[0 0 0 0]
fmt.Println(slices)
// 长度:4, 容量8
fmt.Printf("长度:%d, 容量%d", len(slices), cap(slices))
应该指出的是,golang无法通过下标展开切片。如果需要扩展,就需要使用它。append
slices2 := []int{1,2,3,4}
slices2 = append(slices2, 5)
fmt.Println(slices2)
// 输出结果 [1 2 3 4 5]
同时切片还可以合并两个切片
// 合并切片
slices3 := []int{6,7,8}
slices2 = append(slices2, slices3...)
fmt.Println(slices2)
// 输出结果 [1 2 3 4 5 6 7 8]
应该指出的是,切片会有一个扩容操作,当元素存放不下的时候,会将原来的容量扩大两倍
使用copy()函数复制切片
正如我们前面所知道的,片是对数据类型的引用。
- 值类型:当更改变量的副本时,它不会更改变量本身。
- 引用类型:当您更改变量副本的值时,您将更改变量本身的值。
如果我们需要在不影响原始切片的情况下更改切片的值,则需要使用它。copy函数
// 要复制的切片
var slices4 = []int{1,2,3,4}
// 使用make函数创建切片
var slices5 = make([]int, len(slices4), len(slices4))
// 复制切片的值
copy(slices5, slices4)
// 修改切片
slices5[0] = 4
fmt.Println(slices4)
fmt.Println(slices5)
运行结果为
[1 2 3 4]
[4 2 3 4]
删除切片中的值
Go没有特殊的方法来删除语言中的切片元素。我们可以利用切片本身的特性来删除元素。代码如下
// 删除切片中的值
var slices6 = []int {0,1,2,3,4,5,6,7,8,9}
// 删除下标1的值
slices6 = append(slices6[:1], slices6[2:]...)
fmt.Println(slices6)
运行结果
[0 2 3 4 5 6 7 8 9]
版权声明
所有资源都来源于爬虫采集,如有侵权请联系我们,我们将立即删除