我是数组--就要学习Go语言

栏目: Go · 发布时间: 5年前

内容简介:Go 语言给用户提供了三种数据结构用于管理集合数据:数组、切片(Go语言中,数组是一个长度固定的数据类型,用于存储一段相同数据类型的元素,这些元素在内存中是连续存储的。数组存储的类型可以是内置类型,如整型、字符串等,也可以是自定义的数据结构。强调数组数组声明有两个要点:

Go 语言给用户提供了三种数据结构用于管理集合数据:数组、切片( Slice )和映射( Map )。这三种数据结构是语言核心的一部分,在标准库里被广泛使用。学会这些数据结构,编写 go 程序会变得快速、有趣且十分灵活。掌握数组是理解切片和映射的基础,我们就从数组开始学习。

什么是数组

Go语言中,数组是一个长度固定的数据类型,用于存储一段相同数据类型的元素,这些元素在内存中是连续存储的。数组存储的类型可以是内置类型,如整型、字符串等,也可以是自定义的数据结构。强调数组 固定 ,有别于切片,它是可以增长和收缩的动态序列。数组的每个元素可以通过索引下标来访问,索引下标的范围是从 [0 , len(array)-1]

声明与初始化

数组声明有两个要点:

  1. 指定数组存储的数据的类型;
  2. 元素个数,即数组的长度;
var array0 [5]int   // 声明一个包含5个元素的整型数组,但我们并未初始化
fmt.Println(array0)  //输出:[0 0 0 0 0]
复制代码

前面我们已经讲过,Go 语言中声明变量时,总会使用对应类型的零值来对变量进行初始化。数组也不例外。 当数组初始化时,数组内每个元素都初始化为对应类型的零值。从输出结果可以看到,整型数组里的每个元素都初始化为 0,也就是整型的零值。

var array0 [5]int
array0 = [5]int{1,2,3,4,5}   //手动初始化
fmt.Println(array0)   //输出:[1 2 3 4 5]
复制代码

最基本的声明并初始化:

// 声明并初始化
var array0 = [5]int{1,2,3,4,5}
fmt.Println(array0)
复制代码

使用Go提供的 := 操作符:

array0 := [5]int{1,2,3,4,5}
复制代码

Go提供了一种机制,免去了我们指定数组长度的烦恼,使用 ... ,根据初始化时数组元素的数量来确定该数组的长度。

array := [...]int{1,2,3,4,5}
fmt.Println(len(array))  // 内置的len()函数返回数组中元素的个数。
复制代码

假如我只想给索引为1、3的元素指定初始化的值怎么办?还是有办法的:

array := [...]int{0,2,0,4,0}
复制代码

更简便的方法:

array := [5]int{1:2,3:4}
复制代码

学会使用数组

上面提到过得,因为数组的内存分布是连续的,所以在数组访问任一的效率是很高,这也是数组的优势。可以使用 [] 运算符访问数组的当个元素。

array := [5]int{1,2,3,4,5}
fmt.Println(array[3])    //访问单个元素
array[3] = 30            //修改当个元素的值
fmt.Println(array[3])
复制代码

使用 forfor range 循环遍历数组:

array := [5]int{1,2,3,4,5}
// for
for i:=0;i<len(array);i++ {
	fmt.Printf("索引%d的值: %d\n",i,array[i])
}	
// for range
for i,v := range array{
	fmt.Printf("索引%d的值: %d\n",i,v)
}
	
复制代码

输出的结果是一样的:

索引0的值: 1
索引1的值: 2
索引2的值: 3
索引3的值: 4
索引4的值: 5
复制代码

数组变量的类型包括 数组长度每个元素的类型 。Go语言规定只有这两部分都相同的数组,才是类型相同的数组,才能互相赋值,不然会编译出错。

var array1 [5]int
array2 := [5]int{1,2,3,4,5}
array1 = array2
fmt.Println(array1)   // 输出:[1 2 3 4 5]

var array3 [4]int = array2  
// 编译出错:cannot use array2 (type [5]int) as type [4]int in assignment
复制代码

数组指针和指针数组

我们可以声明一个指针变量,指向一个数组:

arr := [6]int{5:9}
// 数组指针
var ptr *[6]int = &arr
// 简写 
ptr := &arr
复制代码

需要 注意 的是,指针变量 ptr 的类型是 *[6]int ,也就是说它只能指向包含6个元素的整型数组,否则编译报错。 指针数组和数组差不多,只不过元素类型是指针:

// 指针数组
x,y := 1,2
var arrPtr = [5]*int{1:&x,3:&y}  // 没有手动初始化的元素,已经自动初始化指针类型对应的零值 nil
fmt.Println(*arrPtr[1])   // 输出:1

*arrPtr[1] = 10     
fmt.Println(x,*arrPtr[1])  // 输出:10 10
复制代码

*arrPtr[1] = 10 ,同时也修改了变量 x 的值,因为 xarrPtr[1] 指向同一内存地址。 提一点,相同类型的指针数组也可以相互赋值。 总结一句话:注意 *与 谁结合,如 p *[5]int* 与数组结合说明是数组指针;如 p [5]*int*int 结合,说明这个数组都是 int 类型的指针,是指针数组。

函数间传递数组

函数之间传递变量时, 总是以值的方式传递的。如果变量是一个数组,意味着整个数组,不管有多大,都会完整赋值一份,并传递给函数。复制出来的数组只是原数组的一份副本,在函数中修改传递进来数组是不会改变原数组的值得。

// 传递数组的副本
func modify(a [5]int)  {
	a[1] = 1
	fmt.Println(a)
}

func main(){
	arr := [5]int{4:9}
	fmt.Println(arr)
	modify(arr)
	fmt.Println(arr)
}
复制代码

输出:

[0 0 0 0 9]
[0 1 0 0 9]
[0 0 0 0 9]
复制代码

原数组元素的值没有被修改。

大家可以想一个问题,如果一个数组的数据量很大,如果还采用值传递的话,这无疑是一个开销很大的操作,对内存和性能都是不友好的。还好,我们还有一个更好的办法:传递指向数组的指针,这样只需要复制一个数组类型的指针大小就可以。

// 传递数组的指针
func modifyPtr(a *[5]int){
	a[1] = 2
	fmt.Println(*a)
}

func main(){
	arr := [5]int{4:9}
	fmt.Println(arr)
	modifyPtr(&arr)
	fmt.Println(arr)
}
复制代码

输出:

[0 0 0 0 9]
[0 2 0 0 9]
[0 2 0 0 9]
复制代码

有没有发现!原数组已经改变了,因为现在传递的是数组指针, 所以如果改变指针指向的值,原数组在内存的值也会被修改。这种操作虽然更有效地利用内存(免去了大量的内存复制)、性能也更好,但如果没有处理好指针,也会带来不必要的问题,所以,使用的时候需要谨慎小心。

下一节,我们来讲讲切片!

关注公众号「Golang来了」,获取最新文章!

我是数组--就要学习Go语言

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

The Little MLer

The Little MLer

Matthias Felleisen、Daniel P. Friedman、Duane Bibby、Robin Milner / The MIT Press / 1998-2-19 / USD 34.00

The book, written in the style of The Little Schemer, introduces instructors, students, and practicioners to type-directed functional programming. It covers basic types, quickly moves into datatypes, ......一起来看看 《The Little MLer》 这本书的介绍吧!

MD5 加密
MD5 加密

MD5 加密工具

html转js在线工具
html转js在线工具

html转js在线工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换