切片

切片(slice)是对数组一个连续片段的引用(该数组我们称之为相关数组,通常是匿名的),所以切片是一个引用类型(因此更类似于 C/C++ 中的数组类型,或者 Python 中的 list 类型)

切片是一个 长度可变的数组。

多个切片如果表示同一个数组的片段,它们可以共享数据;因此一个切片和相关数组的其他切片是共享存储的,相反,不同的数组总是代表不同的存储。数组实际上是切片的构建块。

优点 因为切片是引用,所以它们不需要使用额外的内存并且比使用数组更有效率,所以在 Go 代码中 切片比数组更常用。

声明切片的格式是: var identifier []type(不需要说明长度)。

一个切片在未初始化之前默认为 nil,长度为 0。

切片也可以用类似数组的方式初始化:var x = []int{2, 3, 5, 7, 11}。这样就创建了一个长度为 5 的数组并且创建了一个相关切片。

切片在内存中的组织方式实际上是一个有 3 个域的结构体:指向相关数组的指针,切片 长度以及切片容量。下图给出了一个长度为 2,容量为 4 的切片。——注意看其中的内存共享方式!!!

  • y[0] = 3 且 y[1] = 5
  • 切片 y[0:4] 由 元素 3, 5, 7 和 11 组成。

注意 绝对不要用指针指向 slice。切片本身已经是一个引用类型,所以它本身就是一个指针!!

7.2.2 将切片传递给函数

如果你有一个函数需要对数组做操作,你可能总是需要把参数声明为切片。当你调用该函数时,把数组分片,创建为一个 切片引用并传递给该函数。这里有一个计算数组元素和的方法:

func sum(a []int) int {
s := 0
for i := 0; i < len(a); i++ {
s += a[i]
}
return s
} func main() {
var arr = [5]int{0, 1, 2, 3, 4}
sum(arr[:])
}

7.2.3 用 make() 创建一个切片

当相关数组还没有定义时,我们可以使用 make() 函数来创建一个切片 同时创建好相关数组:var slice1 []type = make([]type, len)

下图描述了使用 make 方法生成的切片的内存结构:

7.2.4 new() 和 make() 的区别

看起来二者没有什么区别,都在堆上分配内存,但是它们的行为不同,适用于不同的类型。

  • new(T) 为每个新的类型T分配一片内存,初始化为 0 并且返回类型为*T的内存地址:这种方法 返回一个指向类型为 T,值为 0 的地址的指针,它适用于值类型如数组和结构体(参见第 10 章);它相当于 &T{}
  • make(T) 返回一个类型为 T 的初始值,它只适用于3种内建的引用类型:切片、map 和 channel(参见第 8 章,第 13 章)。

换言之,new 函数分配内存,make 函数初始化;下图给出了区别:

在图 7.3 的第一幅图中:

var p *[]int = new([]int) // *p == nil; with len and cap 0
p := new([]int)

在第二幅图中, p := make([]int, 0) ,切片 已经被初始化,但是指向一个空的数组。

以上两种方式实用性都不高。下面的方法:

var v []int = make([]int, 10, 50)

或者

v := make([]int, 10, 50)

这样分配一个有 50 个 int 值的数组,并且创建了一个长度为 10,容量为 50 的 切片 v,该 切片 指向数组的前 10 个元素。

转自:https://github.com/Unknwon/the-way-to-go_ZH_CN/blob/master/eBook/07.2.md

7.6.3 字符串和切片的内存结构

字符串 string s = "hello" 和子字符串 t = s[2:3] 在内存中的结构可以用下图表示:

7.6.8 切片和垃圾回收

切片的底层指向一个数组,该数组的实际容量可能要大于切片所定义的容量。只有在没有任何切片指向的时候,底层的数组内层才会被释放,这种特性有时会导致程序占用多余的内存。

示例 函数 FindDigits 将一个文件加载到内存,然后搜索其中所有的数字并返回一个切片。

var digitRegexp = regexp.MustCompile("[0-9]+")

func FindDigits(filename string) []byte {
b, _ := ioutil.ReadFile(filename)
return digitRegexp.Find(b)
}

这段代码可以顺利运行,但返回的 []byte 指向的底层是整个文件的数据。只要该返回的切片不被释放,垃圾回收器就不能释放整个文件所占用的内存。换句话说,一点点有用的数据却占用了整个文件的内存。

想要避免这个问题,可以通过拷贝我们需要的部分到一个新的切片中:

func FindDigits(filename string) []byte {
b, _ := ioutil.ReadFile(filename)
b = digitRegexp.Find(b)
c := make([]byte, len(b))
copy(c, b)
return c
}

go语言笔记——切片底层本质是共享数组内存!!!绝对不要用指针指向 slice切片本身已经是一个引用类型就是指针的更多相关文章

  1. go语言笔记——append底层实现和Cpp vector无异,只是有返回值,double后返回了新的vector地址而已

    切片的复制与追加 如果想增加切片的容量,我们必须创建一个新的更大的切片并把原分片的内容都拷贝过来.下面的代码描述了从拷贝切片的 copy 函数和向切片追加新元素的 append 函数. 示例 7.12 ...

  2. go语言笔记——多值函数,本质上和nodejs的回调很像,不过nodejs是回调的第一个参数是err,而golang里是第二个!

    5.2 测试多返回值函数的错误 Go 语言的函数经常使用两个返回值来表示执行是否成功:返回某个值以及 true 表示成功:返回零值(或 nil)和 false 表示失败(第 4.4 节).当不使用 t ...

  3. go语言中的数组切片:特立独行的可变数组

    go语言中的数组切片:特立独行的可变数组 初看go语言中的slice,觉得是可变数组的一种很不错的实现,直接在语言语法的层面支持,操作方面比起java中的ArrayList方便了许多.但是在使用了一段 ...

  4. 013-结构体-C语言笔记

    013-结构体-C语言笔记 学习目录 1.[掌握]返回指针的函数 2.[掌握]指向函数的指针 3.[掌握]结构体的声明 4.[掌握]结构体与数组 5.[掌握]结构体与指针 6.[掌握]结构体的嵌套 7 ...

  5. 3.9 Go Slice切片

    3.9 Go Slice切片 Go语言切片(Slice) 切片是可动态变化的序列,是对数组的引用,引用类型,遵循引用传递的机制 slice类型写作[ ]T,T是slice元素类型,var s1 []i ...

  6. 【C语言】超详讲解☀️指针是个什么针?(一次性搞定指针问题)

    目录 前言 一. 什么是指针? 引例 计算机是怎么对内存单元编号的呢? 内存空间的地址如何得到 想存地址怎么办? ​ 本质目的不是为了存地址 二.指针和指针类型 为什么有不同类型的指针 1.指针的解引 ...

  7. go语言笔记——指针,和C用法以及本质一样,但不支持指针的+-运算!

    4.4.2 值类型和引用类型 所有像 int.float.bool 和 string 这些基本类型都属于值类型,使用这些类型的变量直接指向存在内存中的值. Go 语言的取地址符是 &,放到一个 ...

  8. go语言笔记——切片函数常见操作,增删改查和搜索、排序

    7.6.6 搜索及排序切片和数组 标准库提供了 sort 包来实现常见的搜索和排序操作.您可以使用 sort 包中的函数 func Ints(a []int) 来实现对 int 类型的切片排序.例如  ...

  9. GoLang笔记-数组和切片,本质是就是长度不可变的可变的区别

    数组 Arrays 数组是内置(build-in)类型,是一组同类型数据的集合,它是值类型,通过从0开始的下标索引访问元素值.在初始化后长度是固定的,无法修改其长度.当作为方法的入参传入时将复制一份数 ...

随机推荐

  1. Vue核心知识-computed和watch的使用场景和方法

    https://www.jianshu.com/p/bb7a2244c7ca

  2. CAD设置系统变量(com接口VB语言)

    主要用到函数说明: MxDrawXCustomFunction::Mx_SetSysVar 设置系统变量.详细说明如下: 参数 说明 CString sVarName 系统变量名 Value 需要设置 ...

  3. 脚手架工具搭建VUE应用

    首先需要安装node.js,然后安装CLI工具. vue init webpack vue-lesson2 使用element组件的话,需要用到如下命令: cd vue-lesson2 vue add ...

  4. Java编辑编译及运行环境

    Java编辑编译及运行环境 Microsoft Windows 编辑工具 EditPlus JDK JDK(Java Development Kit,Java开发工具包)安装JDK之后,其中bin文件 ...

  5. Intel要在中国投35亿美金造这种闪存,3DxPoint技术牛在哪里?

    Repost: https://www.leiphone.com/news/201508/bbCUJqS2M3glCY3m.html 编者按: 今年的IDF上,Intel 再次强调了3DxPoint闪 ...

  6. Object.prototype 原型和原型链

    Object.prototype 原型和原型链 原型 Javascript中所有的对象都是Object的实例,并继承Object.prototype的属性和方法,有些属性是隐藏的.换句话说,在对象创建 ...

  7. LCS(HDU_5495 循环节)

    传送门:LCS 题意:给出两个序列an和bn,想在给出一个序列pn,问经过a[p1],,,,a[pn]和b[p1],,,b[pn]变换后序列a和序列b的最长公共子序列的长度是多少. 思路:对a[i]- ...

  8. python_ 学习笔记(基本数据类型)

    python3有6中标准数据类型:Number(数字).String(字符串).List(列表).Tuple(元组).Dictionary(字典).Set(集合)不可变数据:Number.String ...

  9. 修改虚拟机中Linux的IP

    联网:ifup eth0 查看ip:ifconfig 点击编辑,选择NAT,子网ip修改第三字段为25,确定,重启linux后,会自动分配字段为25的ip 或者,也可以修改为自己想要的ip,如图:进入 ...

  10. 【模板】51nod 1006 最长公共子序列Lcs

    [题解] dp转移的时候记录一下,然后倒着推出答案即可. #include<cstdio> #include<cstring> #include<algorithm> ...