切片简介

切片也是一种数据类型,在Golang中,切片底层基于数组实现的。
我们定义切片如下

var slice []int

切片之所以出现,是为了更好的利用资源,管理数据,如果使用数组,则我们一开始就要定义数组的长度,而使用切片,则可以不需要定义数组长度。

切片数据结构如下,假设初始化分配容量为6,长度为4的切片。

1. 切片的初始化

在初始化切片阶段,会调用下列源码:

// NewSlice returns the slice Type with element type elem.
func NewSlice(elem *Type) *Type {
    if t := elem.Cache.slice; t != nil {
        if t.Elem() != elem {
            Fatalf("elem mismatch")
        }
        return t
    }

    t := New(TSLICE)
    t.Extra = Slice{Elem: elem}
    elem.Cache.slice = t
    return t
}

从代码可知,上述方法返回的结构体 TSLICE 中的 Extra 字段是一个只包含切片内元素类型的 Slice{Elem: elem} 结构,也就是说切片内元素的类型是在编译期间确定的。

在源码编译期间的切片是 Slice 类型的,但是在运行时切片由如下的 SliceHeader 结构体表示

type SliceHeader struct {
    Data uintptr
    Len  int
    Cap  int
}

Data 字段是指向数组的指针,Len 表示当前切片的长度,而 Cap 表示当前切片的容量。其实Cap也是底层数组的大小。正如图片所示,切片只是在数组上面进行了抽象而成的。

2. 切片的访问

访问切片中元素使用的 OINDEX 操作也会在中间代码生成期间转换成对地址的直接访问:

func (s *state) expr(n *Node) *ssa.Value {
    switch n.Op {
    case OINDEX:
        switch {
        case n.Left.Type.IsSlice():
            p := s.addr(n, false)
            return s.load(n.Left.Type.Elem(), p)
        ...
        }
    ...
    }
}

切片的访问操作基本都是在编译期间完成的.

3. 追加元素

往切片追加元素是我们经常的操作。在 Go 语言中我们会使用 append 关键字向切片追加元素。在追加元素过程中,先对切片结构体进行解构获取它的数组指针、大小和容量,如果在追加元素后切片的大小大于容量。在Go语言中,通过append追加元素,但是并不会主动赋值给原切片,需要手动赋值。

    var slice []int
    slice2 := append(slice, 0)
    fmt.Println(slice)
    fmt.Println(slice2)

输出:

[]
[0]

并且,Go语言考虑到追加元素超过原切片容量时会进行扩容操作。此处到扩容操作会重新申请一段内存,并将原切片元素拷贝过去。

func growslice(et *_type, old slice, cap int) slice {
    newcap := old.cap
    doublecap := newcap + newcap
    if cap > doublecap {
        newcap = cap
    } else {
        if old.len < 1024 {
            newcap = doublecap
        } else {
            for 0 < newcap && newcap < cap {
                newcap += newcap / 4
            }
            if newcap <= 0 {
                newcap = cap
            }
        }
    }

在分配内存空间之前需要先确定新的切片容量,Go 语言根据切片的当前容量选择不同的策略进行扩容:

  1. 如果期望容量大于当前容量的两倍就会使用期望容量;
  2. 如果当前切片容量小于 1024 就会将容量翻倍;
  3. 如果当前切片容量大于 1024 就会每次增加 25% 的容量,直到新容量大于期望容量;

加一道题目,你觉得输出的会是什么:

func main() {
    s := []int{1, 2, 3}
    ss := s[1:]
    ss = append(ss, 4)

    for _, v := range ss {
        v += 10
    }
    for i := range ss {
        ss[i] += 10
    }
    fmt.Println(s)
}

菜鸟系列Golang学习 — 切片的更多相关文章

  1. 菜鸟系列 Golang 实战 Leetcode —— 面试题24. 反转链表

    定义一个函数,输入一个链表的头节点,反转该链表并输出反转后链表的头节点.   示例: 输入: 1->2->3->4->5->NULL 输出: 5->4->3- ...

  2. Golang学习系列:(一)介绍和安装

    Golang学习系列:(一)介绍和安装 Java程序员带你来到Go的世界,让我们开始探索吧! Go是一种新的语言,一种并发的,带有垃圾回收的.快速编译的语言,它具有一下特点: 他可以在一台计算机上用几 ...

  3. golang学习笔记 ---数组与切片

    数组: golang数组包含的每个数据称为数组元素(element),数组包含的元素个数被称为数组长度(length). golang数组的长度在定义后不可更改,并且在声明时可以是一个常量或常量表达式 ...

  4. 上四条只是我目前总结菜鸟们在学习FPGA时所最容易跑偏的地

    长期以来很多新入群的菜鸟们总 是在重复的问一些非常简单但是又让新手困惑不解的问题.作为管理员经常要给这些菜鸟们普及基础知识,但是非常不幸的是很多菜鸟怀着一种浮躁的心态来学习 FPGA,总是急于求成. ...

  5. 开心菜鸟系列----变量的解读(javascript入门篇)

                       console.info(         console.info(window['weiwu'])          console.info(window. ...

  6. 【golang学习记录】环境搭建

    [golang学习记录]环境搭建 一. 概述 本文是[golang学习记录]系列文章的第一篇,安装Go语言及搭建Go语言开发环境,接下来将详细记录自己学习 go 语言的过程,一方面是为了巩固自己学到的 ...

  7. [C#][算法] 用菜鸟的思维学习算法 -- 马桶排序、冒泡排序和快速排序

    用菜鸟的思维学习算法 -- 马桶排序.冒泡排序和快速排序 [博主]反骨仔 [来源]http://www.cnblogs.com/liqingwen/p/4994261.html  目录 马桶排序(令人 ...

  8. golang学习之beego框架配合easyui实现增删改查及图片上传

    golang学习之beego框架配合easyui实现增删改查及图片上传 demo目录: upload文件夹主要放置上传的头像文件,main是主文件,所有效果如下: 主页面: 具体代码: <!DO ...

  9. Golang学习 - 学习资源列表

    Golang 学习资源: <Go 语言圣经(中文版)>  - 书籍 http://shinley.com/index.html <学习 Go 语言> - 书籍 http://w ...

随机推荐

  1. Apsara Clouder云计算专项技能认证:网站建设-简单动态网站搭建

    一.课程介绍 1.课程目标 了解静态网站和动态网站的区别 掌握动态网站的不同实现方式 在阿里云上如何搭建 wordPress网站以及 wordPress 网站的管理和优化 二.网站搭建的类型 1.网站 ...

  2. 72)PHP,session基本原理和登录验证

    (1) (2)   所以  你要是开了session,那么就会有session数据,但是假如在你的php脚本中没有开放发session,就不会有session数据

  3. Pulsar、ZooKeeper、BookKeeper 作用简述

    Pulsar:采取了存储计算分离的技术ZooKeeper 集群的作用和在 Kafka 中是一样的,都是被用来存储元数据.BookKeeper 集群则被用来存储消息数据.BookKeeper 有点儿类似 ...

  4. spring mvc 页面form提示语

    <form:form id="inputForm" modelAttribute="bsRabiesNum" action="${ctx}/nu ...

  5. Android下的鉴权实现方案

    软件原理 不赘述,参考: 软件License认证方案的设计思路 License文件离线鉴权 机械指纹,不可逆的加密算法,如MD5 功能鉴权,可逆的不对称加密算法,服务端公钥加密,app端私钥解密,如R ...

  6. springboot学习笔记:11.springboot+shiro+mysql+mybatis(通用mapper)+freemarker+ztree+layui实现通用的java后台管理系统(权限管理+用户管理+菜单管理)

    一.前言 经过前10篇文章,我们已经可以快速搭建一个springboot的web项目: 今天,我们在上一节基础上继续集成shiro框架,实现一个可以通用的后台管理系统:包括用户管理,角色管理,菜单管理 ...

  7. 树剖裸题——BZOJ1036 树的统计

    #include<cstring> #include<cmath> #include<algorithm> #include<cstdio> #defi ...

  8. 牛客-小y的盒子

    题目传送门 -------------------稍加观察就会发现,4n - 1就是题目要的答案.至于为什么,看官方的题解.不过这个n非常的大,用正常快速幂解决不了.这道题我学到的就是解决幂非常大的情 ...

  9. nodejs 中国汉字模糊查询简单(很low)实现

    https://github.com/cclient/hanzimohusearch 部分代码

  10. async样例

    function iniProcessDetail(isjob) { var cursor = logColl.find({}).sort({ip: 1}); var insertbolk = []; ...