【Go入门学习】理解区分数组和切片
一、前言
学过 Go 的都知道在 Go 语言中有四种复合数据类型:数组、切片(Slice)、哈希表(Map)和结构体(Struct),而很多 Go 初学者也很容易把数组和切片弄混淆,所以要怎么把这两个数据类型分清楚呢?
二、数组
1.简介
数组是聚合类型,是一组同类型数据的集合,通过从0开始的下标索引访问元素值。在 Go 语言中,数组是值类型,这就意味着当你将一个数组赋值给另一个数组的时候,实际上是将这个数组拷贝了一份。
数组的声明语法为:
var 数组变量名 [元素数量]Type
语法说明如下所示:
- 数组变量名:数组声明及使用时的变量名;
- 元素数量:数组的元素数量,可以是一个表达式,但最终计算的结果必须是整型数值;
- Type:可以是任意基本类型,包括数组本身,类型为数组本身时,可以实现多维数组。
2.初始化
默认情况下,数组的每个元素都被初始化为元素类型对应的零值,对于数字类型来说就是0。在数组字面值中,如果在数组的长度位置出现的是“...”省略号,则表示数组的长度是根据初始化值的个数来计算。示例如下:
var a []int
a[] =
b := []int{, }
c := [...]int{, , }
fmt.Println(a) // [1 0 0]
fmt.Println(b) // [1 2]
fmt.Println(c) // [3 5 7]
3.遍历数组
数组通过下标访问元素,可修改其元素值。数组的遍历通过 for 循环实现:
arr := []int{, , }
for i := ; i < ; i++ {
fmt.Printf("%d ", arr[i])
} // 2 4 6
fmt.Println()
for _, v := range arr {
fmt.Printf("%d ", v)
} // 2 4 6
三、切片
1.简介
数组的长度不可改变,在一定场合下就不太适用了,Go 语言则提供了一种可以动态扩容的数据类型--切片(Slice)。一个切片类型通常会写作 []T,其中 T 代表切片中元素的数据类型,切片的语法和数组类似,只是没有固定长度。
2.区别
切片和数组有如下区别:
1)和数组相比,切片除了有长度(len),还有容量(cap),容量指切片当前可容纳元素的最大数量。
2)数组是值类型,切片是引用类型。
值类型和引用类型有什么区别呢?在传递参数时,如果是值类型,对参数修改不会对原来的变量产生影响,但若是引用传递,对参数的修改也会影响到原始数据。示例如下:
package main import (
"fmt"
) func change(a []int, s []int) {
a[] +=
s[] +=
s = append(s, )
} func main() {
arr := []int{, , }
sli := []int{, , }
change(arr, sli)
fmt.Println(arr) // [2 4 6]
fmt.Println(sli) // [4 5 7]
}
在示例中,分别对数组 arr 和切片 sli 的第一个元素进行了+1操作,但从打印结果可以看出来只有切片的数据被修改了,而对数组的修改并没有改变原始数据。那为什么最后 sli 的结果不是 [4 5 7 9]呢?这是因为 append() 实际上是将切片 sli 复制了一份然后赋值给了 s,已经是一份新的数据了,也就不会对 sli 产生影响了。
3.初始化
切片的初始化可以通过数组来实现,也可以通过内置函数 make() 来实现,在使用 make() 方法时还可以设置切片的容量,在追加元素时,若切片的容量不足,则会按切片的长度的二倍进行扩容。示例如下:
arr := []int{, , , , }
s1 := arr[:]
fmt.Println(s1) // [3 4 5]
s2 := arr[:]
fmt.Println(s2) // [1 2 3 4 5]
s3 := make([]int, )
s3[], s3[], s3[] = , ,
fmt.Println(s3) // [2 4 6]
4.追加元素
在 Go 语言中有一个内置函数 append(),查看源码发现它是这么定义的:
func append(slice []Type, elems ...Type) []Type
内置的 append() 函数用于向 slice 追加元素,示例为:
arr := []int{, , , , }
var sli []int
for _, v := range arr {
sli = append(sli, v)
}
fmt.Println(sli) // [1 2 3 4 5]
细心的人会发现源码中写的是 elems,这是不是就意味着可以一次添加多个元素呢?试一试:
var sli []int
sli = append(sli, , , )
fmt.Println(sli) // [1 2 3]
例子很简单,append() 使用起来也很方便,但问题是如果要添加的元素数量超过了切片的容量,又会发生什么情况呢?看下面的例子:
var y []int
for i := ; i < ; i++ {
y = append(y, i)
fmt.Printf("%d cap=%d %v\n", i, cap(y), y)
}
这几行代码的运行结果为:
0 cap=1 [0]
1 cap=2 [0 1]
2 cap=4 [0 1 2]
3 cap=4 [0 1 2 3]
4 cap=8 [0 1 2 3 4]
5 cap=8 [0 1 2 3 4 5]
6 cap=8 [0 1 2 3 4 5 6]
7 cap=8 [0 1 2 3 4 5 6 7]
8 cap=16 [0 1 2 3 4 5 6 7 8]
9 cap=16 [0 1 2 3 4 5 6 7 8 9]
可以发现切片的容量从1慢慢增加为2、4、8、16,也就是说在使用 append 将元素添加至切片时,如果超出了容量,将会返回一个容量二倍与当前切片的切片。
5.切片拷贝
在 Go 语言中,切片的拷贝使用内置函数 copy() 来实现,可以放心的是,切片拷贝是深拷贝,不用像 Python 中纠结深浅拷贝真的很幸福呢!只不过拷贝的时候需要确保目的切片有足够的容量,否则会拷贝。示例如下:
sli := []int{, , }
res := make([]int, )
copy(res, sli)
fmt.Println(res) // [3 5 7 0 0]
fmt.Println(&sli[], &res[]) // 0xc000012340 0xc00000c3c0
var s []int
copy(s, sli)
fmt.Println(s) // []
这里 s 打印出来是空的,是由于 s 在初始化的时候没有分配内存空间,copy() 也不会为 s 分配空间,所以 sli 中的元素也就无法拷贝到 s 中了。
【Go入门学习】理解区分数组和切片的更多相关文章
- go 学习笔记之数组还是切片都没什么不一样
上篇文章中详细介绍了 Go 的基础语言,指出了 Go 和其他主流的编程语言的差异性,比较侧重于语法细节,相信只要稍加记忆就能轻松从已有的编程语言切换到 Go 语言的编程习惯中,尽管这种切换可能并不是特 ...
- Scala入门学习笔记三--数组使用
前言 本篇主要讲Scala的Array.BufferArray.List,更多教程请参考:Scala教程 本篇知识点概括 若长度固定则使用Array,若长度可能有 变化则使用ArrayBuffer 提 ...
- [Golang学习笔记] 07 数组和切片
01-06回顾: Go语言开发环境配置, 常用源码文件写法, 程序实体(尤其是变量)及其相关各种概念和编程技巧: 类型推断,变量重声明,可重名变量,类型推断,类型转换,别名类型和潜在类型 数组: 数组 ...
- 深入学习golang(1)—数组与切片
数据(array)与切片(slice) 数组声明: ArrayType = "[" ArrayLength "]" ElementType . 例如: va ...
- Go语言学习笔记(4)——数组和切片
1 数组的特点: 长度固定.元素数据类型相同.下标从0开始 1.1 声明和初始化: var array_name [size] type var arr1 [10] float32 ...
- Egg入门学习(二)---理解service作用
在上一篇文章 Egg入门学习一 中,我们简单的了解了Egg是什么东西,且能做什么,这篇文章我们首先来看看官网对Egg的整个框架的约定如下,及约定对应的目录是做什么的,来有个简单的理解,注意:我也是按照 ...
- Go语言入门——数组、切片和映射(下)
上篇主要介绍了Go语言里面常见的复合数据类型的声明和初始化. 这篇主要针对数组.切片和映射这些复合数据类型从其他几个方面介绍比较下. 1.遍历 不管是数组.切片还是映射结构,都是一种集合类型,要从这些 ...
- Go语言入门——数组、切片和映射
按照以往开一些专题的风格,第一篇一般都是“从HelloWorld开始” 但是对于Go,思来想去,感觉真的从“HelloWorld”说起,压根撑不住一篇的篇幅,因为Go的HelloWorld太简单了. ...
- opengl入门学习
OpenGL入门学习 说起编程作图,大概还有很多人想起TC的#include <graphics.h>吧? 但是各位是否想过,那些画面绚丽的PC游戏是如何编写出来的?就靠TC那可怜的640 ...
随机推荐
- [ERROR]element select is not allowed here
问题:在使用IDEA搭建springboot项目的时候,在xml文件中遇到element select is not allowed here错误 原因:xml文件的头部的配置有错误,红框的三个地方命 ...
- Java自动生成数据
最近在造数据库中的表数据,写了些数据生成类 可以随机生成姓名.性别,民族,出生日期,身份证号,手机号,邮箱,身高,文化程度,地址,单位,日期时间,编码等 package com.util.create ...
- nyoj 83-迷宫寻宝(二) (计算几何, 叉积)
83-迷宫寻宝(二) 内存限制:10MB 时间限制:1000ms 特判: No 通过数:2 提交数:6 难度:5 题目描述: 一个叫ACM的寻宝者找到了一个藏宝图,它根据藏宝图找到了一个迷宫,这是一个 ...
- 百度全景地图使用时提示flash版本过低 如何处理?
从Chrome 69.0 版本起,Flash权限受到进一步限制,默认仅在当前浏览器会话有效.关闭Enable Ephemeral Flash Permissions ,才能看到 “Add”按钮.解决方 ...
- HashMap的源码学习以及性能分析
HashMap的源码学习以及性能分析 一).Map接口的实现类 HashTable.HashMap.LinkedHashMap.TreeMap 二).HashMap和HashTable的区别 1).H ...
- 记录用户登陆信息,你用PHP是如何来实现的
对于初入门的PHP新手来说,或许有一定的难度.建议大家先看看PHP中session的基础含义,需要的朋友可以选择参考. 下面我们就通过具体的代码示例,为大家详细的介绍PHP中session实现记录用户 ...
- STDN: Scale-Transferrable Object Detection论文总结
概述 STDN是收录于CVPR 2018的一篇目标检测论文,提出STDN网络用于提升多尺度目标的检测效果.要点包括:(1)使用DenseNet-169作为基础网络提取特征:(2)提出Scale-tra ...
- Markdown学习笔记(一)
解决Markdown文件插入图片无法只能本地查看的问题 原因:图片的显示与图片地址关联,写入Markdown时用的本机地址,一旦上传到网络,地址就发生了变化,也就显示不了图片. 寻找免费的图床网站. ...
- websrom编译器
webstorm less环境配置 备注: 安装node后,在命令行输入npm install -g less 即可安装less,打开webstorm setting-Tools-FileWatche ...
- createTextNode
createTextNode()方法将创建一个包含给定文本的新文本文档节点.这个方法的返回值是一个指向新建文本节点的引用指针: reference = document.createTextNode( ...