数组、切片

数组

如何定义数组

数组是具有相同类型且长度固定的一组连续数据。数组元素可以通过索引(位置)来读取(或者修改),索引从0开始,第一个元素索引为 0,第二个索引为 1,以此类推。在go语言中我们可以使用如下几种方式来定义数组。

//方式一
var arr1 = [5]int{}
//方式二
var arr2 = [5]int{1,2,3,4,5}
//方式三
var arr3 = [5]int{3:10}
//方式四var arr3 = []float32{1000.0, 2.0, 3.4, 7.0, 50.0}

输出以上三个变量的值如下所示:

arr1 [0 0 0 0 0]
arr2 [1 2 3 4 5]
arr3 [0 0 0 10 0]
arr3 [1000 2 3.4 7 50]

  • 方法一在声明时没有为其指定初值,所以数组内的值被初始化为类型的零值。
  • 方法二使用显示的方式为数组定义初值。
  • 方法三通过下标的方式为下标为3的位置赋上了初值10
  • 方法四在申明时,并未指定数组大小,通过数组元素来确定数组大小
  • 初始化数组中 {} 中的元素个数不能大于 [] 中的数字

而且在数组的定义是包含其长度的,也就是说[3]int与[4]int是两种不同的数据类型。

如何操作数据

在上面的arr1我们没有为其指定初值,那么之后我们可以通过循环的方式为其赋予初值

for i := 0; i < len(arr1); i++ {arr1[i] = i * 10}

此时我们再输出一下数组arr1,可以看到其值已经变化

arr1 update:  [0 10 20 30 40]

我们还可以通过循环的方式遍历数组,与上面不同的是,for循环提供这样的方式来为便利数组

for index, value := range arr1 {fmt.Printf("index: %d, value: %dn", index, value)}

通过range来遍历数组会有两个返回值,其中第一个为数组的索引,第二个位置为对应的值,输出结果如下:

index: 0, value: 0
index: 1, value: 10
index: 2, value: 20
index: 3, value: 30
index: 4, value: 40

当然不想要索引值也是可以的,可以用_代替。

多维数组

二维数组是最简单的多维数组,二维数组本质上是由一维数组组成的。二维数组定义方式如下:

var arrayName [ x ][ y ] variable_type

variable_type 为 Go 语言的数据类型,arrayName 为数组名,二维数组可认为是一个表格,x 为行,y 为列,下图演示了一个二维数组 a 为三行四列:

二维数组中的元素可通过** a i **来访问。

与其他语言一样,go语言也可以定义多维数组,可以选择的定义方式如下:

// 方式一
func main() {var arr4 = [5][5]int{{1, 2, 3, 4, 5},{6, 7, 8, 9, 10},}fmt.Println(arr4)
}// 方式二
func main() {a := [3][4]int{{0, 1, 2, 3} ,   /*  第一行索引为 0 */{4, 5, 6, 7} ,   /*  第二行索引为 1 */{8, 9, 10, 11} ,   /*  第三行索引为 2 */}fmt.Println(a)
}

输出当前数组,可以看到数组内的值如下所示

// 方式一
[[1 2 3 4 5] [6 7 8 9 10] [0 0 0 0 0] [0 0 0 0 0] [0 0 0 0 0]]
// 方式二
[[0 1 2 3] [4 5 6 7] [8 9 10 11]]

数组作为函数参数

go语言在传递数组时会对其进行拷贝,所以如果传递的是大数组的话会非常占内存,所以一般情况下很少直接传递一个数组,避免这种情况我们可以使用以下两种方式:

  • 传递数组的指针
  • 传递切片(具体内容见下一小节)

向函数传递数组参数,你需要在函数定义时,声明形参为数组,我们可以通过以下两种方式来声明:

方式一

形参设定数组大小:

void myFunction(param [10]int){}

方式二

形参未设定数组大小:

void myFunction(param []int){}

实例

让我们看下以下实例,实例中函数接收整型数组参数,另一个参数指定了数组元素的个数,并返回平均值:

func getAverage(arr []int,size int) float32{var i intvar avg, sum float32
​for i = 0; i < size; ++i {sum += arr[i]}
​avg = sum / size
​return avg;
}

接下来我们来调用这个函数:

package main
​
import "fmt"
​
func main() {/* 数组长度为 5 */var  balance = []int {1000, 2, 3, 17, 50}var avg float32
​/* 数组作为参数传递给函数 */avg = getAverage( balance, 5 ) ;
​/* 输出返回的平均值 */fmt.Printf( "平均值为: %f ", avg );
}
func getAverage(arr []int, size int) float32 {var i,sum intvar avg float32
​for i = 0; i < size;i++ {sum += arr[i]}
​avg = float32(sum / size)
​return avg;
}

以上实例执行输出结果为:

平均值为: 214.000000

以上实例中我们使用的形参并为设定数组大小。

指针数组与数组指针

对于指针数组和数组指针在c或c++中也经常被讨论,尤其对于初学者来说会分辨不清楚。其实在每个词中间添加一个“的“就很好理解了,指针的数组,数组的指针。

1.指针数组

对于指针数组来说,就是:一个数组里面装的都是指针,在go语言中数组默认是值传递的,所以如果我们在函数中修改传递过来的数组对原来的数组是没有影响的。

func main() {var a [5]intfmt.Println(a)test(a)fmt.Println(a)
}
​
​
func test(a [5]int) {a[1] = 2fmt.Println(a)
}

输出

[0 0 0 0 0]
[0 2 0 0 0]
[0 0 0 0 0]

但是如果我们一个函数传递的是指针数组,情况会有什么不一样呢?

func main() {var a [5]*intfmt.Println(a)for i := 0; i < 5; i++ {temp := ia[i] = &temp}for i := 0; i < 5; i++ {fmt.Print(" ", *a[i])}fmt.Println()test1(a)for i := 0; i < 5; i++ {fmt.Print(" ", *a[i])}
}
​
​
func test1(a [5]*int) {*a[1] = 2for i := 0; i < 5; i++ {fmt.Print(" ", *a[i])}fmt.Println()
}

我们先来看一下程序的运行结果

[<nil> <nil> <nil> <nil> <nil>]0 1 2 3 40 2 2 3 40 2 2 3 4

可以看到初始化值全是nil,也就验证了指针数组内部全都是一个一个指针,之后我们将其初始化,内部的每个指针指向一块内存空间。

注:在初始化的时候如果直接另a[i] = &i那么指针数组内部存储的全是同一个地址,所以输出结果也一定是相同的

然后我们将这个指针数组传递给test1函数,对于数组的参数传递仍然是复制的形式也就是值传递,但是因为数组中每个元素是一个指针,所以test1函数复制的新数组中的值仍然是这些指针指向的具体地址值,这时改变a[1]这块存储空间地址指向的值,那么原实参指向的值也会变为2,具体流程如下图所示。

2.数组指针

了解了指针数组之后,再来看一下数组指针,数组指针的全称应该叫做,指向数组的指针,在go语言中我们可以如下操作。

func main() {var a [5]intvar aPtr *[5]intaPtr = &a//这样简短定义也可以aPtr := &afmt.Println(aPtr)test(aPtr)fmt.Println(aPtr)
}
​
​
func test(aPtr *[5]int) {aPtr[1] = 5fmt.Println(aPtr)
}

我们先定义了一个数组a,然后定一个指向数组a的指针aPtr,然后将这个指针传入一个函数,在函数中我们改变了具体的值,程序的输出结果

&[0 0 0 0 0]
&[0 5 0 0 0]
&[0 5 0 0 0]

通过上面的图我们可以看见虽然main和test函数中的aPtr是不同的指针,但是他们都指向同一块数组的内存空间,所以无论在main函数还是在test函数中对数组的操作都会直接改变数组。

切片

因为数组是固定长度的,所以在一些场合下就显得不够灵活,所以go语言提供了一种更为便捷的数据类型叫做切片。切片操作与数组类似,但是它的长度是不固定的,可以追加元素,如果以达到当前切片容量的上限会再自动扩容。

如何定义切片

可以通过以下几种方式定义切片

//方法一
var s1 = []int{}
//方法二
var s2 = []int{1, 2, 3}
//方法三
var s3 = make([]int, 5)
//方法四
var s4 = make([]int, 5, 10)

方法一声明了一个空切片,方法二声明了一个长度为3的切片,方法三声明了一个长度为5的空切片,方法四声明了一个长度为5容量为10的切片。可以看到切片的定义与数组类似,但是定义切片不需要为其指定长度。

我们可以通过len()cap()这两个函数来获取切片的长度和容量,下面就来依次看下上面各切片的长度以及容量。

s1 [] 0 0
s2 [1 2 3] 3 3
s3 [0 0 0 0 0] 5 5
s4 [0 0 0 0 0] 5 10

如果我们通过这种方式定义一个切片,那么他会被赋予切片的空值nil。

var s5 []int

切片操作

我们可以通过如下的方式在数组和切片上继续获取切片

func main() {arr := [5]int{1, 2, 3, 4, 5}s := []int{6, 7, 8, 9, 10}
​s1 := arr[2:4]s2 := arr[:3]s3 := arr[2:]s4 := s[1:3]
​fmt.Println("s1:", s1)fmt.Println("s2:", s2)fmt.Println("s3:", s3)fmt.Println("s4:", s4)
}

程序的输出结果如下

s1: [3 4]
s2: [1 2 3]
s3: [3 4 5]
s4: [7 8]

可以看到切片操作是“包左不包右”,例如arr[2:4]是选择arr数组内下标为2,3的两个元素。如果:左边没有起始位置则默认从头开始,同理如果右边没有终止位置则默认到末尾。

切片的扩充与拼接

我们之前介绍了切片的定义以及一些切片的操作,下面就来看一下如何对切片进行扩充。

func main() {a := []int{1, 2, 3}b := a[1:3]
​b = append(b, 4)b = append(b, 5)b = append(b, 6)b = append(b, 7)fmt.Println(a)fmt.Println(b)
}

程序输出结果如下

[1 2 3]
[2 3 4 5 6 7]

如果想要将两个切片进行拼接可以使用如下这种方式:

func main() {a := []int{1, 2, 3}b := a[1:3]
​fmt.Println(b)
​a = append(a, b...)fmt.Println(a)
}
​
>>[2 3]
>>[1 2 3 2 3]

如果我们想要将一个切片的值复制给另一个切片,go语言也提供了非常简便的方式。

func main() {a := []int{1, 2, 3}b := make([]int, 3)copy(b, a)fmt.Println(a)fmt.Println(b)
}
>>[1 2 3]
>>[1 2 3]

你不妨动手试一试下面几个操作结果会怎么样:

  • 声明b切片时,其长度比a切片长,复制结果是怎么样的?
func main() {    a := []int{1, 2, 3}    b := make([]int, 5)    copy(b, a)    fmt.Println(a)    fmt.Println(b)
}
>>[1 2 3]
>>[1 2 3 0 0]

  • 声明b切片时,其长度比a切片短,复制结果是怎么样的?
func main() {a := []int{1, 2, 3, 4, 5}b := make([]int, 3)copy(b, a)fmt.Println(a)fmt.Println(b)
}
​
>>[1 2 3 4 5]
>>[1 2 3]

  • 声明b切片时,其长度被定义为0,那么调用copy函数会报错吗?

    • No
func main() {a := []int{1, 2, 3, 4, 5}b := make([]int, 0)copy(b, a)fmt.Println(a)fmt.Println(b)
}
>>[1 2 3 4 5]
>>[]

切片与数组的关系

对于任何一个切片来说,其都有一个底层数组与之对应,我们可以将切片看作是一个窗口,透过这个窗口可以看到底层数组的一部分元素。

既然切片是引用底层数组的,需要注意的就是小切片引用大数组的问题,如果底层的大数组一直有切片进行引用,那么垃圾回收机制就不会将其收回,造成内存的浪费,最有效的做法是copy需要的数据后再进行操作。

go int 转切片_DW-Go语言编程-Task06-数组、切片相关推荐

  1. c语言数组的一维编程,C语言编程一维数组的使用.doc

    C语言编程一维数组的使用 实验 一维数组的使用 [实验目的 1掌握数组定义和初始化方法. 2熟悉使用字符数组处理字符串处理的方法.实验内容10个学生的成绩,求平均成绩,并将低于平均成绩的分数打印出来. ...

  2. c语言数组判断不及格人数,C语言编程 运用数组求不及格人数

    C语言编程题,求数组89,80,95,84,73,84,91,78,87,94的和以及平均值 #includevoid main(){ int a[10]={89,80,95,84,73,84,91, ...

  3. python切片输出_Python语言之详解切片

    本篇文章主要讲述Python语言之详解切片,希望阅读本篇文章以后大家有所收获,帮助大家对相关内容的理解更加深入. 切片操作就是对list,元组,字符串进行截取操作有了切片操作,很多地方循环就不再需要了 ...

  4. c语言编程输出数组元素之和,C语言 输出一个数组中,所有元素之和为0的子序列...

    本程序用到了一个时间种子,来随机产生10个整数[-5~5],函数是randData( ).还有一个计算子序列为0的函数ZeroSubarray( ). randData( )如下: int arr[1 ...

  5. c语言编程数组例题,c语言编程有关数组的几道例题.docx

    实验四 一维数组.二维数组 一.实验目的与要求 1.熟练掌握一维数组.二维数组的定义.赋值和输入输出的方法. 2.掌握与数组有关的算法. 二.实验内容 1.(1)输入N个整数,使用冒泡排序,将数据由大 ...

  6. 【Go语言编程】基础知识篇

    文章目录 一.Go语言简介 1.优势 2.劣势 3.前景 二.数据集的导入及编辑 1.包及其导入 2.变量 3.预定义常量 4.基础数据类型 5.派生数据类型 6.类型转换与类型别名 三.流程控制 四 ...

  7. c语言编程统计学生个数,c编程统计并显示500至800之间所有素数的总个数以及总和...

    编一个程序,输入10个整数,统计并输出其中正数.负数和零的个数.要求用C语言编程. #includemain(){intt,i,c0=0,c1=0,c2=0;for(i=0;i excel 统计某列数 ...

  8. 打印20以内的素数c语言,c语言编程输出2~100之间的所有素数(每行输出10个),并将它们打印出来....

    C语言编程实现计算1到100之间的奇数之和 你好,可以这样编程]#includeintmain(){inti,sum=0;//定义循环变量和存放求和的变量sumfor(i=1;i C语言:用for循环 ...

  9. c语言中英翻译及程序设计,c语言编程英语词汇带翻译

    c语言编程英语词汇带翻译 在c语言的.学习过程中,会需要用到大量的专业英语词汇,所以学习c语言方面的专业英语词汇的学习非常重要,那么现在就一起来学习一些c语言专业词汇吧. c语言编程英语词汇 cras ...

  10. C语言计算级数fun,c语言编程 编写函数fun(),它的功能是:计算和输出下列级数的和....

    用C语言编程,已知f(x)=(1+x^2),编写函数用梯形法计算f(x)在区间[a,b]上的定积分 #includevoidmain(){doublei,j;doublea,b,c=0;printf( ...

最新文章

  1. R语言使用car包的durbinWatsonTest函数检验回归模型的响应变量(或者残差)是否具有独立性(Independence、是否具有自相关关javascript系autocorrelated)
  2. Hive学习笔记 —— Hive的管理
  3. Serverless的理解
  4. main函数解析(一)——Linux-0.11 学习笔记(五)
  5. 华为手机安装系统能换鸿蒙,华为鸿蒙将全面上线,安卓系统或将被彻底替换
  6. cocos2d-x知识总结
  7. SQL入门试炼创建表
  8. Markdown简明使用
  9. bzoj2208:[Jsoi2010]连通数
  10. wifi协议_图解 802.11wifi协议
  11. spring-第十三篇之零配置支持
  12. tm影像辐射定标_ENVI中TM的辐射定标和大气校正
  13. 超详细 Windows 系统安装教程
  14. 【软件工程/系统软件/程序设计语言】 2019年-中国计算机学会推荐国际学术会议和期刊目录(四)
  15. Redis的几种数据结构的特点
  16. 基于遗传算法在机器人路径规划中的应用研究(Matlab代码实现)
  17. 苹果耳机安卓手机可以用吗_想知道安卓手机用一年会卡,苹果手机不卡,这个问题出现在那吗...
  18. python协同过滤电影推荐的论文_协同过滤?教你用Python实现协同过滤
  19. 计算机专业用移动硬盘,评测 篇四十三:国产之光,看这款可做移动硬盘又可系统盘的Orico SSD...
  20. 解决“Win 10 ipv6无网络权限/无Internet连接权限”问题

热门文章

  1. 设计模式——策略模式(C++实现)
  2. 2017.3.24组合数学学习——容斥原理
  3. gcc/g++/makefile/easymake/cmake/xmake/nmake ...
  4. Hadoop: MapReduce2的几个基本示例
  5. [Silverlight]常见问题
  6. 数据聚集技术在mondrian中的实现
  7. win10:tensorflow学习笔记(2)
  8. 【C语言】字节对齐问题(以32位系统为例)
  9. Java一行代码打印当前系统时间
  10. python封装sql脚本 github_Github 大牛封装 Python 代码,实现自动发送邮件只需三行代码...