go语言中切片Slice与数组Array对比以及panic: runtime error: index out of range问题解决

目录
  • 前言
  • 一、go slice是什么
  • 二、go slice实战案例
    • 1.slice创建、使用
    • 2、slice的长度和容量概念理解
    • 3. 切片扩容及slice panic: runtime error: index out of range
  • 附:go 判断数组下标是否存在
  • 总结

前言

在go语言的学习历程当中,slice数据类型引起了我的好奇心。为啥不直接使用Slice,是人性的扭曲还是道德的沦丧~,下面让我们一探究竟~~

一、go slice是什么

go语言中的slice是一个基于Array封装的数据结构,go语言中slice的使用频率远高于array,其身影频频出现在源码实现当中。slice相对于Array的优点就是其可以动态调整自己的size,不像Array的Size是固定的。

二、go slice实战案例

1.slice创建、使用

slice的创建有两个方法分别是使用字面量定义和使用make函数。除过slice创建,其他slice的生成办法均是从现有slice分片或者array上做slice分片操作。

slice创建代码:

package main

import (
	"fmt"
	"reflect"
)

func main() {
	//字面创造Slice
	sliceOne := []string{"a", "b"}
	//使用make函数创造slice
	sliceTwo := make([]string, 10)
	sliceThree := make([]int, 10)

	fmt.Printf("使用字面量创建的slice%s\n",reflect.ValueOf(sliceOne).String())
	fmt.Printf("使用make函数创建的slice:%s\n",reflect.ValueOf(sliceTwo).String())
	fmt.Printf("使用make函数创建的slice:%s\n",reflect.ValueOf(sliceThree).String())

}

程序输出:

使用字面量创建的slice<[]string Value>
使用make函数创建的slice:<[]string Value>
使用make函数创建的slice:<[]int Value>
 
Process finished with the exit code 0

2、slice的长度和容量概念理解

学习过程中,很多小伙伴会对slice的长度和容量问题有着很多混淆。

这个地方可以把切片比喻成一个可以装10个苹果的袋子,现在的袋子里面有三颗苹果。切片的长度就是袋子已经装的果子的个数,目前是3个。切片的容量就是这个袋子一共能装多少个果子,对于这个袋子来说就是10。那么把代码替换成切片,把苹果替换成元素,是不是就懂了撒~

下面就是该问题的处理办法就是直接去官方,看源码。看看第一手资料怎么讲!

长度:slice中拥有的元素个数,如果slice是nil的话,则元素个数长度是0
英文:the number of elements in v; if v is nil, len(v) is zero

容量:slice切片的长度能够到达的最大值
英文:Slice: the maximum length the slice can reach when resliced;

代码验证环节:

package main

import (
    "fmt"
 )

func main() {
    sliceOne := []string{"a", "b"}
    strings := sliceOne[0:1]
    fmt.Printf("切片的长度:%d\n",len(strings))
    fmt.Printf("切片的容量:%d\n",cap(strings))
}

代码结果输出:

切片的长度:1
切片的容量:2

代码原理解析:

strings由sliceOne切片而来,切出来的片上数据有的是0到1,有一个元素,故其对应的长度是1。

因为切片是一个引用类型,只在原始切片上切出了0到1的位置,剩余的空位还有1,故其容量等于长度加剩余元素位置数。

3. 切片扩容及slice panic: runtime error: index out of range

slice越界代码实例如下:

    sliceOne := []string{"a", "b"}
    //使用make函数创造slice
    s := sliceOne[2]
    fmt.Printf(s)

使用sliceOne[2]语句时,数组越界报错。

实际开发过程中,总会有slice容量不够用的时候,该怎么扩容,如何保证安全扩容?

go语言官方提供的扩容办法就是创建一个新的更大的分片,将老分片的数据内容迁移到新的切片当中。

代码展示:

package main

import (
    "fmt"
 )

func main() {
    sliceOne := []string{"a", "b"}
    fmt.Printf("切片扩容前")
    fmt.Printf("切片的长度:%d\n",len(sliceOne))
    fmt.Printf("切片的容量:%d\n",cap(sliceOne))
    t := make([]string, len(sliceOne), (cap(sliceOne))*2)
    copy(t, sliceOne)
    sliceOne = t
    fmt.Printf("切片扩容后")
    fmt.Printf("切片的长度:%d\n",len(sliceOne))
    fmt.Printf("切片的容量:%d\n",cap(sliceOne))
}

结果展示:

切片的长度:2
切片的容量:2
切片的长度:2
切片的容量:4

从代码结果上看出新切片的长度是2,容量是4,也再次验证了切片的长度取决于存放了多少元素,切片的容量取决于已存放的元素数量加剩余位置数。

附:go 判断数组下标是否存在

举例

现在需要判断命令行是否传了参数,即 os.Args[1] 是否存在

如果使用下述的判断:

func main() {
    fmt.Println(os.Args[1])
}

会报错:index out of range

panic: runtime error: index out of range [1] with length 1
 
goroutine 1 [running]:
main.main()
        D:/go_work/test/test4.go:9 +0xbc
exit status 2

现有两种方式解决:

第一种:

通过遍历的方式判断 key 是否存在

func main() {
    var result string
    for k, v := range os.Args {
        if k == 1 {
            result = v
        }
    }
    if result != "" {
        fmt.Printf("os.Args[1] = %s", result)
    }
}

第二种:

由于数组下标从0开始,len(arr)-1 为最后一个元素的下标,所以判断所要查询的 key 是否小于 len(arr) 就可以了

func main() {
    if len(os.Args)>=2 {
        fmt.Printf("os.Args[1] = %s", os.Args[1])
    }
}

总结

go语言中slice的应用和使用相对来说方便快捷很多,不过也有一些小小的暗坑等待大家发现和整理哦~后续我会在我的博客中,继续发布有关于go语言使用的tips和技巧~

到此这篇关于go语言中切片Slice与数组Array对比以及panic: runtime error: index out of range问题解决的文章就介绍到这了,更多相关go语言切片Slice和数组Array内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Go语言入门教程之Arrays、Slices、Maps、Range操作简明总结

    Arrays:数组 在go语言中数组array是一组特定长度的有序的元素集合. 复制代码 代码如下: package main import "fmt" func main() { //这里我们创建了一个长度为5的数组. 这一组数组的初值是zero-valued.整型就是0     var a [5]int     fmt.Println("emp:", a) //可以通过array[index] = value语法赋值     a[4] = 100     fmt

  • 理解Golang中的数组(array)、切片(slice)和map

    我比较喜欢先给出代码,然后得出结论 数组 复制代码 代码如下: package main import (     "fmt" ) func main() {     arr := [...]int{1, 2, 3}     //打印初始的指针     fmt.Printf("the pointer is : %p \n", &arr)     printPointer(arr) } func printPointer(any interface{}) {

  • GO语言数组和切片实例详解

    本文实例讲述了GO语言数组和切片的用法.分享给大家供大家参考.具体分析如下: 一.数组 与其他大多数语言类似,Go语言的数组也是一个元素类型相同的定长的序列. (1)数组的创建. 数组有3种创建方式:[length]Type .[N]Type{value1, value2, ... , valueN}.[...]Type{value1, value2, ... , valueN} 如下: 复制代码 代码如下: func test5() {     var iarray1 [5]int32    

  • Go语言中的Array、Slice、Map和Set使用详解

    Array(数组) 内部机制 在 Go 语言中数组是固定长度的数据类型,它包含相同类型的连续的元素,这些元素可以是内建类型,像数字和字符串,也可以是结构类型,元素可以通过唯一的索引值访问,从 0 开始. 数组是很有价值的数据结构,因为它的内存分配是连续的,内存连续意味着可是让它在 CPU 缓存中待更久,所以迭代数组和移动元素都会非常迅速. 数组声明和初始化 通过指定数据类型和元素个数(数组长度)来声明数组. 复制代码 代码如下: // 声明一个长度为5的整数数组 var array [5]int

  • Golang 拷贝Array或Slice的操作

    Golang中Array是值类型而slice是引用类型.因此两者之间的赋值或拷贝有些差异,本文带你了解各自的差异. 1. 拷贝array 前面提及数组是值类型,所以数组变量名不是指向第一个元素的指针.事实上它表示整个数组,下面两者情况将自动创建数组: 数组变量赋值给另一个数组变量 数组变量传递作为函数参数 请看示例: package main import "fmt" func main() { sample1 := [2]string{"a", "b&q

  • go结构体嵌套的切片数组操作

    看代码吧~ package main import ( "fmt" ) type XCDataStu struct { Id int `json:"id" xorm:"id"` Name string `json:"name" xorm:"name"` } type XCDataStu1 struct { Id int `json:"id" xorm:"id"` St

  • 深入理解Go语言中的数组和切片

    一.类型 数组是值类型,将一个数组赋值给另一个数组时,传递的是一份拷贝. 切片是引用类型,切片包装的数组称为该切片的底层数组. 我们来看一段代码 //a是一个数组,注意数组是一个固定长度的,初始化时候必须要指定长度,不指定长度的话就是切片了 a := [3]int{1, 2, 3} //b是数组,是a的一份拷贝 b := a //c是切片,是引用类型,底层数组是a c := a[:] for i := 0; i < len(a); i++ { a[i] = a[i] + 1 } //改变a的值后

  • go语言中切片Slice与数组Array对比以及panic: runtime error: index out of range问题解决

    目录 前言 一.go slice是什么 二.go slice实战案例 1.slice创建.使用 2.slice的长度和容量概念理解 3. 切片扩容及slice panic: runtime error: index out of range 附:go 判断数组下标是否存在 总结 前言 在go语言的学习历程当中,slice数据类型引起了我的好奇心.为啥不直接使用Slice,是人性的扭曲还是道德的沦丧~,下面让我们一探究竟~~ 一.go slice是什么 go语言中的slice是一个基于Array封

  • Golang中的Slice与数组及区别详解

    在golang中有数组和Slice两种数据结构,Slice是基于数组的实现,是长度动态不固定的数据结构,本质上是一个对数组字序列的引用,提供了对数组的轻量级访问.那么我们今天就给大家详细介绍下Golang中的Slice与数组, 1.Golang中的数组 数组是一种具有固定长度的基本数据结构,在golang中与C语言一样数组一旦创建了它的长度就不允许改变,数组的空余位置用0填补,不允许数组越界. 数组的一些基本操作:      1.创建数组: func main() { var arr1 = [.

  • 详解Go语言中切片的长度与容量的区别

    目录 切片的声明 切片的长度和容量 切片追加元素后长度和容量的变化 append 函数 切片的源代码学习 切片的结构体 切片的扩容 总结 切片的声明 切片可以看成是数组的引用(实际上切片的底层数据结构确实是数组).在 Go 中,每个数组的大小是固定的,不能随意改变大小,切片可以为数组提供动态增长和缩小的需求,但其本身并不存储任何数据. // 数组的声明 var a [5]int //只指定长度,元素初始化为默认值0 var a [5]int{1,2,3,4,5} // 切片的声明 // 方法1:

  • 一文带你深入了解Go语言中切片的奥秘

    目录 Go语言基础三 切片的定义 创建切片的方式 切片初始化 Go语言基础三 切片的定义 1. 切片:切片是数组的一个引用,因此切片是引用类型.但自身是结构体,值拷贝传递. 2. 切片的长度可以改变,因此,切片是一个可变的数组. 3. 切片遍历方式和数组一样,可以用len()求长度.表示可用元素数量,读写操作不能超过该限制. 4. cap可以求出slice最大扩张容量,不能超出数组限制.0 <= len(slice) <= len(array),其中array是slice引用的数组. 5. 切

  • go语言中切片的长度和容量的区别

    切片的长度,显而易见的就是元素的个数,根据元素的个数进行返回具体的长度. 切片的长度,更像是一个警戒值,如果长度与容量相等,就会进行容量的扩容,比如 des :=make([]int , 3 , 5) //此时,长度为3,容量为5,但是如果使用append(), //切片长度会变为4,再次使用append()切片长度变为5. //此时,切片长度与容量相同,此时,切片的容量增大变为cap = len*2 也就是通过一个容量设警戒值,如果等于警戒值,就会自动将切片进行扩容 补充:Go语言中切片的长度

  • 详解C语言中的函数、数组与指针

    1.函数:当程序很小的时候,我们可以使用一个main函数就能搞定,但当程序变大的时候,就超出了人的大脑承受范围,逻辑不清了,这时候就需要把一个大程序分成许多小的模块来组织,于是就出现了函数概念:   函数是C语言代码的基本组成部分,它是一个小的模块,整个程序由很多个功能独立的模块(函数)组成.这就是程序设计的基本分化方法: (1) 写一个函数的关键: 函数定义:函数的定义是这个函数的实现,函数定义中包含了函数体,函数体中的代码段决定了这个函数的功能: 函数声明:函数声明也称函数原型声明,函数的原

  • 详解C语言中的指针与数组的定义与使用

    指针的特点 他就是内存中的一个地址 指针本身运算 指针所指向的内容是可以操作的 操作系统是如何管理内存的 栈空间 4M~8m的大小 当进入函数的时候会进行压栈数据 堆空间 4g的大小 1g是操作系统 全局变量 内存映射 可以对内存的内容修改修改硬盘的内容 一般在数据库中经常使用 内存的分配与释放 c语言分配内存的方法 // malloc(需要分配的大小): 这里的分配的大小需要对齐的2的指数 void *mem = malloc(size); 释放内存 // 一般分配的内容都是在堆空间中的 //

  • c语言中字符串与字符串数组详解

    目录 字符串 字符串输出 输入字符串 字符串常用方法 字符串数组 总结 字符串 用双引号引起来的就是字符串,字符串由字符组成 字符串使用%s格式化输出 字符串以\0结尾,没有\0就不是字符串 只要是用双引号括起来的都是字符串 字符串的本质就是数组 注意: 字符串变量和普通的字符数组有一定的区别,C语言规定,字符串必须以\0结尾(作为字符串的结束符号),所以字符串变量的元素个数比字符数组的元素多一个\0 #include <stdio.h> int main(int argc, const ch

  • C语言与java语言中关于二维数组的区别

    目录 C语言数中二维数组的定义格式 Java语言中二维数组的定义与初始化 静态初始化 动态初始化 下面给出两者的对比截图 C语言中的数组元素分布 Java中的数组元素分布 数组是编程语言中常用的数据结构,然而在不同的环境下,其定义及初始化的方式也不尽相同.下面来讲述一下C和Java中对于二维数组定义的区别以及其背后的原理. 在C语言中,二维数组的初始化可以省略行数,但不能省略列数:而在java中却是正好相反的,即列数可以省略,而行数是不能省略的.为什么会是这样呢?首先我们来回顾一下C和Java中

  • Go语言中切片使用的注意事项小结

    前言 Go 语言中的slice类型可以理解为是数组array类型的描述符,包含了三个因素: 指向底层数组的指针 slice目前使用到的底层数组的元素个数,即长度 底层数组的最大长度,即容量 因此当我们定义一个切片变量,s := make([]int, 5, 10),即为指向了一个最大长度为10的底层数组,目前切片s使用到的长度为5. 在使用切片的时候,有几个注意事项,下面来一起看看吧. 使用append 先看一个例子: // 创建一个整型切片 // 其长度和容量都是 5 个元素 slice :=

随机推荐