首页 > 其他分享 >数组和切⽚ - Go语言从入门到实战

数组和切⽚ - Go语言从入门到实战

时间:2023-10-20 10:04:28浏览次数:36  
标签:和切 Q2 入门 int 元素 切片 索引 数组 Go


数组和切⽚ - Go语言从入门到实战

数组的声明

package main  
  
import "fmt"  
  
func main() {  
 var a [3]int //声明并初始化为默认零值  
 a[0] = 1  
 fmt.Println("a:", a) // 输出: a: [1 0 0]  
  
 b := [3]int{1, 2, 3} //声明同时初始化  
 fmt.Println("b:", b) // 输出: b: [1 2 3]  
  
 c := [2][2]int{{1, 2}, {3, 4}} //多维数组初始化  
 fmt.Println("c:", c) // 输出: c: [[1 2] [3 4]]  
}

数组元素遍历

与其他主要编程语⾔的差异

func TestTravelArray(t *testing.T) {  
    a := [...]int{1, 2, 3, 4, 5} // 这个数组有5个元素  
    for idx, elem := range a {  
        fmt.Println(idx, elem) // 打印索引和元素值  
    }  
}

与其他一些编程语言(如C或Java)不同,Go语言的数组索引是从0开始的。在上面的示例中,第一个元素的索引是0,第二个元素的索引是1,依此类推。
Go语言中的数组是值类型,当你将数组作为参数传递给函数时,会创建一个数组的副本。如果你想在函数内部修改原始数组的元素,需要传递数组的指针。切片则不同,它们是引用类型,传递切片时会共享底层数组。

数组截取、切片

在Go语言中,可以使用切片(slice)来实现数组的截取。切片是对数组的一个连续片段的引用,可以通过指定开始索引和结束索引来定义。
代码示例:

//a[开始索引(包含), 结束索引(不包含)]

a := [...]int{1, 2, 3, 4, 5}  
  
// a[1:2] 截取从索引1到索引2(不包含)的元素,结果为 [2]  
slice1 := a[1:2]  
fmt.Println(slice1) // 输出: [2]  
  
// a[1:3] 截取从索引1到索引3(不包含)的元素,结果为 [2, 3]  
slice2 := a[1:3]  
fmt.Println(slice2) // 输出: [2 3]  
  
// a[1:len(a)] 截取从索引1到数组末尾的元素,结果为 [2, 3, 4, 5]  
slice3 := a[1:len(a)]  
fmt.Println(slice3) // 输出: [2 3 4 5]  
  
// a[1:] 截取从索引1到数组末尾的元素,结果为 [2, 3, 4, 5]  
slice4 := a[1:]  
fmt.Println(slice4) // 输出: [2 3 4 5]  
  
// a[:3] 截取从数组开始到索引3(不包含)的元素,结果为 [1, 2]  
slice5 := a[:3]  
fmt.Println(slice5) // 输出: [1 2]

切片内部结构

数组和切⽚ - Go语言从入门到实战_开发语言

type slice struct {  
    array unsafe.Pointer // 底层数组的指针,指向切片所引用的数组的首个元素的地址。
    len   int            // 切片的长度,即切片当前包含的元素个数。  
    cap   int            // 切片的容量,即从切片的起始位置到底层数组的末尾的元素个数。容量表示了可以在不重新分配内存的情况下,切片可以容纳的元素数量。  
}

切⽚声明

var s0 []int		//声明了一个名为s0的切片,该切片的元素类型为int。s0是一个空切片,长度为0,容量为0。
s0 = append(s0, 1)		//使用append函数将整数1添加到s0切片的末尾。由于s0的容量为0,因此会自动分配内存空间以容纳新元素。s0的长度为1,容量大于1。
s := []int{}		//声明并初始化了一个名为s的切片,该切片的元素类型为int。s是一个空切片,长度为0,容量为0。
s1 := []int{1, 2, 3}		//声明并初始化了一个名为s1的切片,该切片的元素类型为int,并指定了初始元素为1、2和3。此时,s1的长度为3,容量大于或等于3。
s2 := make([]int, 2, 4) 		//使用make函数创建了一个名为s2的切片,该切片的元素类型为int,长度为2,容量为4。s2的前两个元素会被初始化为整数类型的默认零值(即0),而后续的元素则未初始化且不可访问。

 /*
 []type, len, cap
 其中len个元素会被初始化为默认零值,未初始化元素不可以访问
 */

切⽚共享存储结构

数组和切⽚ - Go语言从入门到实战_GO语言从入门到实战_02


图片看起来很绕,可以用代码来解释,展示了在Go语言中切片如何共享底层数组的内存。在这个示例中,有一个名为year的字符串切片,它包含了12个月份的名称。然后,通过切片操作,创建了两个新的切片Q2和summer,它们分别引用了year切片的不同片段。

func TestSliceShareMemory(t *testing.T) {
	year := []string{"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep",
		"Oct", "Nov", "Dec"}
	Q2 := year[3:6]		
	//Q2 := year[3:6]:创建了一个名为Q2的切片,它引用了year切片从索引3到索引5的元素(不包括索引6)。
	t.Log(Q2, len(Q2), cap(Q2))		
	//输出Q2的内容、长度和容量。此时,Q2的内容为["Apr", "May", "Jun"],长度为3,容量为9(与year切片的容量相同)。
	summer := year[5:8]		
	//创建了一个名为summer的切片,它引用了year切片从索引5到索引7的元素(不包括索引8)。
	t.Log(summer, len(summer), cap(summer))		
	//输出summer的内容、长度和容量。此时,summer的内容为["Jun", "Jul", "Aug"],长度为3,容量为9(与year切片的容量相同)。
	summer[0] = "Unknow"		
	//将summer切片的第一个元素修改为"Unknow"。由于summer和Q2切片共享底层数组的内存,这个修改也会影响到Q2切片对应位置的元素。
	t.Log(Q2)		
	//输出修改后的Q2切片的内容。此时,Q2的内容变为["Unknow", "May", "Jun"]。
	t.Log(year)		
	//输出修改后的year切片的内容。此时,year切片的内容也受到了影响,变为"Jan", "Feb", "Mar", "Apr", "Unknow", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"。
	
}

数组 vs. 切⽚

  1. 容量是否可伸缩:
  • 数组:数组在声明时需要指定元素个数,一旦创建后,其长度和容量都是固定的,无法改变。这意味着数组的大小是固定的,无法根据需要进行扩展或缩小。
  • 切片:切片是对底层数组的一个连续片段的引用,它具有动态大小的特性。切片的长度可以根据需要进行扩展或缩小,而容量也可以根据需要进行增长。这是通过append函数实现的,当切片的长度超过容量时,append函数会自动分配新的底层数组,并将原始数据复制到新的数组中。
  1. 是否可以进行比较:
  • 数组:在Go语言中,数组是值类型,这意味着它们可以进行直接比较。两个数组只有在长度相等且对应位置的元素都相等时才被认为是相等的。
  • 切片:切片是引用类型,它们不可以进行直接比较。切片的比较需要逐个元素进行比较,或者可以使用reflect.DeepEqual函数来进行深度比较。这是因为切片包含了一个指向底层数组的指针,而指针的比较并不是直接比较底层数据的内容。

reflect.DeepEqual函数会递归地比较两个值的结构和具体的元素。对于切片、映射和结构体等复杂数据类型,它会逐个比较它们的元素或字段。

package main  
  
import (  
 "fmt"  
 "reflect"  
)  
  
func main() {  
 slice1 := []int{1, 2, 3}  
 slice2 := []int{1, 2, 3}  
 slice3 := []int{4, 5, 6}  
  
 fmt.Println(reflect.DeepEqual(slice1, slice2)) // 输出: true  
 fmt.Println(reflect.DeepEqual(slice1, slice3)) // 输出: false  
}

学习Go语言主要是多练,多找些代码段写写,不懂可以私聊咨询。

标签:和切,Q2,入门,int,元素,切片,索引,数组,Go
From: https://blog.51cto.com/u_3135183/7946895

相关文章

  • Map声明、元素访问及遍历、⼯⼚模式、实现 Set - GO语言从入门到实战
    Map声明、元素访问及遍历-GO语言从入门到实战Map声明的方式m:=map[string]int{"one":1,"two":2,"three":3} //m初始化时就已经设置了3个键值对,所以它的初始长度len(m)是3。m1:=map[string]int{}//m1被初始化为一个空的map,然后通过m1["one"]=1添加了一个键值......
  • Android入门教程 | RecyclerView使用入门
    想必大家对列表的表现形式已经不再陌生。手机上有联系人列表,文件列表,短信列表等等。本文讲述的是在Android开发中用RecyclerView来实现列表效果。使用步骤引入RecyclerView在app的build.gradle文件中添加引用。我们使用的是androidx包。gradle:dependencies{//........
  • Android入门教程 | DrawerLayout 侧滑栏
    DrawerLayout是实现了侧滑菜单效果的控件。DawerLayout分为侧边菜单和主内容区两部分:主内容区要放在侧边菜单前面,还有就是主内容区最好以DrawerLayout最好为界面的根布局,否则可能会出现触摸事件被屏蔽的问题。侧滑菜单部分的布局必须设置layout_gravity属性,表示侧滑菜单是在......
  • go 格式化json
    packagemainimport("bytes""encoding/json""fmt")funcmain(){//原始JSON字符串varjsonStr=[]byte(`{"Name":"Gopher","Title":"Programmer","Contact":......
  • 解决:Exception: URL fetch failure on https://storage.googleapis.com/tensorflow/tf
    首次装载IMDB数据集时可能会出现的错误。解决方案:1、先将数据集单独下载下来:datasets/imdb.npz·黄健/keras-datasets-Gitee.com2、将其复制到 ~/.keras/dataset目录下:cpimdb.npz ~/.keras/dataset ......
  • Metropolis Algorithms for Representative Subgraph Sampling
    目录概主要内容MetropolisgraphsamplingH\¨{u}blerC.andKriegelH.,BorgwardtK.andGhahramaniZ.Metropolisalgorithmsforrepresentativesubgraphsampling.ICDM,2008.概提出了一种尽可能保持拓扑结构的子图采样方法.主要内容假设我们有一个大图\(G\),......
  • 【Django | 开发】中间件配置(记录响应耗时日志)
    ......
  • Go内存管理
    1.存储基础知识1.1计算机的存储体系从上至下依次是:CPU寄存器、Cache、内存、硬盘等辅助存储设备、鼠标等外接设备说明:从上至下,访问速度越来越慢,访问时间越来越长1.2内存1)物理内存通过物理内存条而获得的内存空间,这种存储是没有写入硬盘的,在计算机关机后就会丢失2)虚拟内......
  • ChatGPT入门实战课 AI时代更具竞争力的开发者[网盘完整]
    点击下载:ChatGPT入门实战课AI时代更具竞争力的开发者[网盘完整]  提取码:vvtwChatGPT是一家全球抢先的人工智能公司,具有强大的技术实力和创新才能。为了协助开发者更好地理解ChatGPT的技术和应用,我们推出了ChatGPT入门实战课,协助开发者成为更具竞争力的AI时期开发者。ChatGPT入......
  • celery包结构、celery延迟任务和定时任务、django中使用celery、接口缓存、双写一致性
    celery包结构project├──celery_task #celery包  这个包可以放在任意位置│├──__init__.py#包文件│├──celery.py#celery连接和配置相关文件,且名字必须叫celery.py│└──tasks.py#所有任务函数│├──add_task.p......