数组是具有相同唯一类型的一组已编号且长度固定的数据项序列(这是一种同构的数据结构);这种类型可以是任意的原始类型例如整形、字符串或者自定义类型(结构体、接口)。数组长度必须是一个常量表达式,并且必须是一个非负整数,数组下标是从0开始的,并且数组的长度是固定不可变的,数组中元素的地址是连续的。数组长度也是数组类型的一部分,所以[5]int和[10]int是属于不同类型的。

在其它编程语言中,数组一般都是引用类型,而在Go语言中,数组属于值类型。

注意:如果我们想让数组元素类型为任意类型的话可以使用空接口作为类型。当使用值时我们必须先做一个类型判断。

声明数组

Go语言数组声明需要指定元素类型及元素个数,语法格式如下:

//  变量名          [大小]类型
var variable_name [len]variable_type

示例:

定义一个长度为5的数组arr

var arr [5]int

以上我们声明了一个数组arr,但是我们还没有对他进行初始化,但是声明的变量都会有默认值,int类型的变量默认值是0,所以arr数组中的每个元素的值都是0。

Go语言中的数组是一种值类型,所以可以通过 new() 来创建: var arr1 = new([5]int) 。那么这种方式和 var arr2 [5]int 的区别是什么呢?arr1 的类型是 *[5]int ,而 arr2的类型是 [5]int

数组在内存的结构

假如我们声明一个长度为5的数组var arr [5]int,我们来看看这个数组在内存中的结构是怎么样的。

上图就是一个Go语言数组在内存的结构,在这个arr数组中,由于我们声明的是int32类型,所以数组中的每个元素在内存中占用的字节数是32/8=4字节,通过arr数组每个元素16进制地址我们可以发现,数组中后一个元素的地址比前一个元素的地址大4个字节,这个4字节正好是int32类型元素占用的内存大小,由此我们也能得出结论:数组中元素的内存地址是连续的;当声明数组时所有的元素都会被自动初始化为数组类型的默认值(int类型的默认值是0,所以arr中每个元素的默认值都是0);数组的下标识从0开始的。数组arr的地址就是数组第一个元素(下标为0的元素)的地址,通过下图打印arr的地址和arr[0]的地址就可以证明

初始化数组

刚刚声明的数组已经被默认的元素类型零值初始化了,如果我们再次进行初始化怎么做呢,可以采用如下办法:

var arr [5]int
arr = [5]int{1, 2, 3, 4, 5}

Go语言提供了声明加初始化的:=操作符,以让我们在创建数组的时候直接初始化。

arr := [5]int{1, 2, 3, 4, 5}

这种简短变量声明的方式不仅适用于数组,还适用于任何数据类型,这也是Go语言中常用的方式。

我们也可以在定义数组是不明确指定长度,让编译器自动推导出长度,可以使用...来替代具体的长度

arr := [...]int{1, 2, 3, 4, 5}

如果我们只想给数组的部分元素指定值,其他元素采用默认值我们可以采用下面的办法

arr := [5]int{0:3, 4:6}

这种方式表示我们只给数组下标为0的元素赋值为3,下标为4的元素赋值为6,其它元素的值依然是该类型的默认值(int的默认值是0)。

使用数组

数组元素的访问非常简单,通过索引(下标)即可访问数组的元素。

arr := [5]int{1, 2, 3, 4, 5}
fmt.Println(arr[0], arr[1], arr[2], arr[3], arr[4])

修改数组的某个元素也很简单:

arr := [5]int{1, 2, 3, 4, 5}
fmt.Println(arr[0])
arr[0] = 66
fmt.Println(arr[0])

如果我们要循环打印数组中的所有值,一个传统的就是常用的for循环:

for i := 0; i < len(arr); i++ {
fmt.Println(arr[i])
}

不过大部分时候,我们都是使用for rang循环:

for i, v := range arr {
fmt.Println("索引是:", i, "值是:", v)
}

同样类型的数组是可以相互赋值的,不同类型的不行,会编译错误。那么什么是同样类型的数组呢?Go语言规定,必须是长度一样,并且每个元素的类型也一样的数组,才是同样类型的数组。

arr := [5]int{1, 2, 3, 4, 5}

var arr2 [5]int = arr //可以
var arr3 [3]int = arr //不可以

指针数组和数组本身差不多,只不过元素类型是指针。

arr := [5]*int{1: new(int), 3:new(int)}

这样就创建了一个指针数组,并且为索引1和3都创建了内存空间,其他索引是指针的零值nil,这时候我们要修改指针变量的值也很简单,如下即可:

array := [5]*int{1: new(int), 3:new(int)}
*array[1] = 1

以上需要注意的是,只可以给索引1和3赋值,因为只有它们分配了内存,才可以赋值,如果我们给索引0赋值,运行的时候,会提示无效内存或者是一个nil指针引用。

panic: runtime error: invalid memory address or nil pointer dereference

要解决这个问题,我们要先给索引0分配内存,然后再进行赋值修改。

arr := [5]*int{1: new(int), 3:new(int)}
arr[0] =new(int)
*arr[0] = 2
fmt.Println(*arr[0])

函数间传递数组

在Go中,数组也是值类型,所以在函数间传递变量时,么就会整个复制,并传递给函数,如果数组非常大,比如长度100多万,那么这对内存是一个很大的开销。

func main() {
array := [5]int{1: 2, 3:4} //[0 2 0 4 0]
modify(array)
fmt.Println(array) //[0 2 0 4 0]
} func modify(a [5]int){
a[1] = 3
}

通过上面的例子,可以看到,数组是复制的,原来的数组没有修改。我们这里是5个长度的数组还好,如果有几百万怎么办,有一种办法是传递数组的指针,这样,复制的大小只是一个数组类型的指针大小。

func main() {
array := [5]int{1: 2, 3:4} //[0 2 0 4 0]
modify(&array)
fmt.Println(array) //[0 333 0 4 0]
} func modify(a *[5]int){
a[1] = 333
}

这里注意,数组的指针和指针数组是两个概念,数组的指针是*[5]int,指针数组是[5]*int,注意*的位置。

数组使用注意事项

  1. 数组是多个相同类型数据的组合,一个数组一旦声明/定义了,其长度是固定的,不能动态变化。

  2. 数组中的元素可以是任何数据类型,包括值类型和引用类型,但是不能混用。

  3. 数组创建后,如果没有赋值,有默认值

    数值类型数组:默认值为0

    字符串类型数组:默认值为""

    bool数组: 默认值为false

    指针数组: 默认值nil

  4. 使用数组的步骤:1.声明数组并开辟空间2.给数组各个元素赋值3.使用数组

  5. 数组的下标从0开始

  6. 数组下标必须在指定范围内使用,否则报panic:数组越界

  7. Go的数组属于值类型 ,在默认情况下是值传递,因此会进行值拷贝。数组间不会相互影响

  8. 如果想在其它函数中,去修改原来的数组,可以使用引用传递(指针方式)

  9. 长度是数组类型的一部分,在传递函数参数时,需要考虑数组的长度

Go语言数组的更多相关文章

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

    本文实例讲述了GO语言数组和切片的用法.分享给大家供大家参考.具体分析如下: 一.数组 与其他大多数语言类似,Go语言的数组也是一个元素类型相同的定长的序列. (1)数组的创建. 数组有3种创建方式: ...

  2. C语言 数组 列优先 实现

    C语言数组结构列优先顺序存储的实现 (GCC编译). 从行优先转换为列优先存储方式, 与行优先相比, 不同之处在于改变了数组维界基址的先后顺序, 从而改变了映像函数常量基址. /** * @brief ...

  3. C语言 数组 行优先 实现

    C语言数组结构行优先顺序存储的实现 (GCC编译). /** * @brief C语言 数组 行优先 实现 * @author wid * @date 2013-11-02 * * @note 若代码 ...

  4. 不可或缺 Windows Native (5) - C 语言: 数组

    [源码下载] 不可或缺 Windows Native (5) - C 语言: 数组 作者:webabcd 介绍不可或缺 Windows Native 之 C 语言 数组 示例cArray.h #ifn ...

  5. C语言数组

    在C语言中,对于三维或三维以上数组的使用并没有很好的支持,而且使用率也非常的低,后面会对三维数组做一些简单的分析,这篇文章主要以二维数组来探讨一些C语言中数组使用的相关概念和技巧. 1 一个var[i ...

  6. C语言数组:C语言数组定义、二维数组、动态数组、字符串数组

    1.C语言数组的概念 在<更加优美的C语言输出>一节中我们举了一个例子,是输出一个 4×4 的整数矩阵,代码如下: #include <stdio.h> #include &l ...

  7. Go语言数组的使用

    Go 语言数组 Go 语言提供了数组类型的数据结构. 数组是具有相同唯一类型的一组已编号且长度固定的数据项序列,这种类型可以是任意的原始类型例如整形.字符串或者自定义类型. 相对于去声明number0 ...

  8. Go 语言数组

    Go 语言提供了数组类型的数据结构. 数组是具有相同唯一类型的一组已编号且长度固定的数据项序列,这种类型可以是任意的原始类型例如整形.字符串或者自定义类型. 相对于去声明number0, number ...

  9. C语言 > 数组和指针

    C语言 数组和指针 const: 关于指针和const需要注意一些规则.首先,把const数据或非const数据的地址初始化为指向const的指针或为其赋值是合法的. 然而,只能把非const数据的地 ...

  10. Go语言数组和切片的原理

    目录 数组 创建 访问和赋值 切片 结构 初始化 访问 追加 拷贝 总结 数组和切片是 Go 语言中常见的数据结构,很多刚刚使用 Go 的开发者往往会混淆这两个概念,数组作为最常见的集合在编程语言中是 ...

随机推荐

  1. Kubernetes 1.3.1 快速单机部署

    Kubernetes发展到今天, 在官网上已经有非常多的成熟部署方案, 但是由于墙的原因, 最简单的MiniKube都无法进行, 参考了以下两篇文章后, 终于安装成功. k8s-1.13版本测试环境搭 ...

  2. 201771010134杨其菊《面向对象程序设计java》第十周学习总结

    第8章泛型程序设计学习总结 第一部分:理论知识 主要内容:   什么是泛型程序设计                   泛型类的声明及实例化的方法               泛型方法的定义      ...

  3. 树莓派3 开机自启动(SPI)

    转自:https://www.raspberrypi-spy.co.uk/2014/08/enabling-the-spi-interface-on-the-raspberry-pi/ 方案一:图形界 ...

  4. form表单上传图片文件

    import os def upload(request): if request.method == 'GET': img_list = models.Img.objects.all() retur ...

  5. 图解Golang的GC算法

    虽然Golang的GC自打一开始,就被人所诟病,但是经过这么多年的发展,Golang的GC已经改善了非常多,变得非常优秀了. 以下是Golang GC算法的里程碑: v1.1 STW v1.3 Mar ...

  6. 当Vue中img的src是动态渲染时不显示问题

    最近遇见动态渲染img时,想起了当初刚开始写vue时,曾经遇见的一个小小坑. Vue中:img的src属性是动态渲染时不显示问题1.需求:展示用户头像,数据从后台获取,如果没有拿到则显示默认图片. 如 ...

  7. JavaScript中的闭包永远都存储在内存中,除非关闭浏览器

    //閉包實現累加功能 function fn1() { var n = 1; add = function() { n += 1; } function fn2() { n += 1; console ...

  8. java GUI的效果图

    import java.awt.*;import javax.swing.*; public class GridBagDemo extends JFrame {    public static v ...

  9. short s=1;s=s+1;short s=1;s+=1;有什么区别?

    short s = 1; s = s + 1; 这个编译一定是不通过的,会提示损失精度. short s = 1; s += 1: 这个编译反而可以通过. 隐式类型转换可以由小到大自动转,即byte ...

  10. 非root用户安装cuda和cudnn

    1.根据自己的系统在官网下载cuda (选择runfile(local)) https://developer.nvidia.com/cuda-downloads 2.进入下载目录,并执行 sh cu ...