详解go语言的array和slice 【二】

简介:   上一篇  详解go语言的array和slice 【一】已经讲解过,array和slice的一些基本用法,使用array和slice时需要注意的地方,特别是slice需要注意的地方比较多。上一篇的最后讲解到创建新的slice时使用第三个索引来限制slice的容量,在操作新slice时,如果新slice的容量大于长度时,添加新元素依然后使源的相应元素改变。

  上一篇  详解go语言的array和slice 【一】已经讲解过,array和slice的一些基本用法,使用array和slice时需要注意的地方,特别是slice需要注意的地方比较多。上一篇的最后讲解到创建新的slice时使用第三个索引来限制slice的容量,在操作新slice时,如果新slice的容量大于长度时,添加新元素依然后使源的相应元素改变。这一篇里我会讲解到如何避免这些问题,以及迭代、和做为方法参数方面的知识点。

slice的长度和容量设置为同一个值

  如果在创建新的slice时我们把他的长度和容量的值设置为样的值,那么在append新元素时,底层会创建一个新的array并把之前的值复制过去。这样就不会影响之前共同的底层array了。

    // 创建一个容量和长度均为6的slice
    slice1 := []int{5, 23, 10, 2, 61, 33}
    // 对slices1进行切片,长度为2容量为3
    slice2 := slice1[1:3:3]
    fmt.Println("cap", cap(slice2))
    fmt.Println("slice2", slice2)

    //修改一个共同指向的元素
    //两个slice的值都会修改
    slice2[0] = 11111
    fmt.Println("slice1", slice1)
    fmt.Println("slice2", slice2)

    // 增加一个元素
    slice2 = append(slice2, 55555)

    fmt.Println("slice1: ", slice1)
    fmt.Println("slice2: ", slice2)

  输出结果

cap 2
slice2 [23 10]
slice1 [5 11111 10 2 61 33]
slice2 [11111 10]
slice1:  [5 11111 10 2 61 33]
slice2:  [11111 10 55555]

  代码中的长度和容量是一样的,长度和容量的计算公式看我的上一篇博客。增加一个元素后,原来共同指向的底层数据是没有变的。因为slice2的底层array被重新赋值了。

迭代slice

  go语言内置一个关键字range用于迭代集合,当然他也可以迭代slice,也可以使用  _  来忽略我们不关心的元素,但是如果只关心index则不需这么写 for index,_ := range slice1。下在给出完整代码

    // 创建一个容量和长度均为6的slice
    slice1 := []int{5, 23, 10, 2, 61, 33}

    for index, value := range slice1 {
        fmt.Println("index: ", index, " value: ", value)
    }

    // 可以忽略我们不关心的元素
    // 只关心value
    for _, value := range slice1 {
        fmt.Println("value ", value)
    }

    // 只关心index, 可以不用 _
    for index := range slice1 {
        fmt.Println("index: ", index)
    }

 

   需要注意的是rang 迭代的value值并是一个复本,我们可以对比一下迭代的value和原slice内相应index下value的地址:

    // 创建一个容量和长度均为6的slice
    slice1 := []int{5, 23, 10, 2, 61, 33}

    for index, value := range slice1 {
        fmt.Println("index: ", index, " value address : ", &value, " slice1 value address", &slice1[index])

    }

  输出结果

index:  0  value address :  0xc04204e088  slice1 value address 0xc04206a030
index:  1  value address :  0xc04204e088  slice1 value address 0xc04206a038
index:  2  value address :  0xc04204e088  slice1 value address 0xc04206a040
index:  3  value address :  0xc04204e088  slice1 value address 0xc04206a048
index:  4  value address :  0xc04204e088  slice1 value address 0xc04206a050
index:  5  value address :  0xc04204e088  slice1 value address 0xc04206a058

  slice1中value的地址是不断变化的。而迭代的value值的地址没有变化,这是因为value是一个变量,为次迭代的时候赋不同的值。我们把代码写成下面这样,你就清楚了

    var index, value int
    for index, value = range slice1 {
        fmt.Println("index: ", index, &index, " value address : ", &value, " slice1 value address", &slice1[index])

    }

   除了使用rang 也可以使用传统的for循环来做迭代

    slice1 := []int{5, 23, 10, 2, 61, 33}
    
    for i, len := 1, len(slice1); i < len; i++ {
        fmt.Println("index: ", i, " value:", slice1[i])
    }

 

 slice作为方法参数

   由于slice的特殊结构,有一个指针指向一个数组

    s := make([]int, 2, 5)
    fmt.Println("len: ", len(s))
    fmt.Println("cap: ", cap(s))
    s = append(s, 2)

    s[0] = 12

 

  所以,slice做为方法的参数传递时,只会复制slice本身而不会复制slice底层的array.如果我们创建一个int类型有100万长度的slice ,把他传递给一个方法时,只需要复制24个字节就够了。指针需要8个,长度和容量都是8个。

const size int = 1000 * 1000

func main() {
    slice0 := make([]int, size)
    fmt.Println("slice0 len: ", len(slice0), " cap :", cap(slice0))
    doSomeThing(slice0)
}

func doSomeThing(s []int) {
    fmt.Println(len(s))
}

 

 

目录
相关文章
|
Go 索引
详解go语言的array和slice 【一】
  本篇会详细讲解go语言中的array和slice,和平时开发中使用时需要注意的地方,以免入坑。   Go语言中array是一组定长的同类型数据集合,并且是连续分配内存空间的。   声明一个数组 var arr [3]int   数组声明后,他包含的类型和长度都是不可变的.如果你需要更多的元素,你只能重新创建一个足够长的数组,并把原来数组的值copy过来。
1071 0
|
9天前
|
程序员 Go PHP
为什么大部分的 PHP 程序员转不了 Go 语言?
【9月更文挑战第8天】大部分 PHP 程序员难以转向 Go 语言,主要因为:一、编程习惯与思维方式差异,如语法风格和编程范式;二、学习成本高,需掌握新知识体系且面临项目压力;三、职业发展考量,现有技能价值及市场需求不确定性。学习新语言虽有挑战,但对拓宽职业道路至关重要。
39 10
|
7天前
|
Go API 开发者
深入探讨:使用Go语言构建高性能RESTful API服务
在本文中,我们将探索Go语言在构建高效、可靠的RESTful API服务中的独特优势。通过实际案例分析,我们将展示Go如何通过其并发模型、简洁的语法和内置的http包,成为现代后端服务开发的有力工具。
|
9天前
|
算法 程序员 Go
PHP 程序员学会了 Go 语言就能唬住面试官吗?
【9月更文挑战第8天】学会Go语言可提升PHP程序员的面试印象,但不足以 solely “唬住” 面试官。学习新语言能展现学习能力、拓宽技术视野,并增加就业机会。然而,实际项目经验、深入理解语言特性和综合能力更为关键。全面展示这些方面才能真正提升面试成功率。
31 10
|
9天前
|
编译器 Go
go语言学习记录(关于一些奇怪的疑问)有别于其他编程语言
本文探讨了Go语言中的常量概念,特别是特殊常量iota的使用方法及其自动递增特性。同时,文中还提到了在声明常量时,后续常量可沿用前一个值的特点,以及在遍历map时可能遇到的非顺序打印问题。
|
7天前
|
存储 监控 数据可视化
Go 语言打造公司监控电脑的思路
在现代企业管理中,监控公司电脑系统对保障信息安全和提升工作效率至关重要。Go 语言凭借其高效性和简洁性,成为构建监控系统的理想选择。本文介绍了使用 Go 语言监控系统资源(如 CPU、内存)和网络活动的方法,并探讨了整合监控数据、设置告警机制及构建可视化界面的策略,以满足企业需求。
24 1
|
13天前
|
安全 大数据 Go
深入探索Go语言并发编程:Goroutines与Channels的实战应用
在当今高性能、高并发的应用需求下,Go语言以其独特的并发模型——Goroutines和Channels,成为了众多开发者眼中的璀璨明星。本文不仅阐述了Goroutines作为轻量级线程的优势,还深入剖析了Channels作为Goroutines间通信的桥梁,如何优雅地解决并发编程中的复杂问题。通过实战案例,我们将展示如何利用这些特性构建高效、可扩展的并发系统,同时探讨并发编程中常见的陷阱与最佳实践,为读者打开Go语言并发编程的广阔视野。
|
11天前
|
存储 Shell Go
Go语言结构体和元组全面解析
Go语言结构体和元组全面解析
|
16天前
|
Go
golang语言之go常用命令
这篇文章列出了常用的Go语言命令,如`go run`、`go install`、`go build`、`go help`、`go get`、`go mod`、`go test`、`go tool`、`go vet`、`go fmt`、`go doc`、`go version`和`go env`,以及它们的基本用法和功能。
25 6
|
16天前
|
存储 Go
Golang语言基于go module方式管理包(package)
这篇文章详细介绍了Golang语言中基于go module方式管理包(package)的方法,包括Go Modules的发展历史、go module的介绍、常用命令和操作步骤,并通过代码示例展示了如何初始化项目、引入第三方包、组织代码结构以及运行测试。
18 3