• 【Golang】快速复习指南QuickReview(二)——切片slice


    切片Slice

    在上一篇【Golang】快速复习指南QuickReview(一)——字符串string的字符串翻转代码实现中,提到了切片,切片在golang中是很重要的数据类型。说到切片,就不得不提数组,但是数组的长度是固定的并且数组长度属于类型的一部分,所以数组有很多的局限性。而切片(Slice)是可变长度的,其实切片是基于数组类型做了一层封装,所以切片会指向一个底层数组。切片新增元素,当切片指向的底层数组能够容纳,则直接新增元素,当底层数组不能容纳新增的元素时,切片就会自动按照一定的策略进行“扩容”,此时该切片指向的底层数组就会更换。

    切片有两个非常重要的属性,长度(len),容量(cap),前者是切片已经包含的元素数量,后者是切片的首指针(第一个元素)指向的底层数组索引至底层数组最后一个元素的长度。

    1.C#的泛型集合List

    根据切片的特性,博主类比的是C#中泛型集合,也会有类似长度与容量等属性,包括自动扩容,但是博主并不清楚扩容算法是否一致,有兴趣的朋友可以自行查阅。

    //实例化 初始化
    List<string> ls = new List<string> { "北京", "上海", "广州", "深圳" };
    
    //输出容量与长度
    Console.WriteLine($"the capacity of citylist is {ls.Capacity},and the length of citylist is {ls.Count}");
    
    //新增元素
    ls.Add("成都");
    
    //再次输出容量与长度
    Console.WriteLine($"the capacity of citylist is {ls.Capacity},and the length of citylist is {ls.Count}");
    
    //删除元素
    ls.Remove("成都");
    
    //再次输出容量与长度
    Console.WriteLine($"the capacity of citylist is {ls.Capacity},and the length of citylist is {ls.Count}");
    
    //遍历元素
    foreach (string city in ls)
    {
    
    }
    
    the capacity of citylist is 4,and the length of citylist is 4
    the capacity of citylist is 8,and the length of citylist is 5
    the capacity of citylist is 8,and the length of citylist is 4
    

    另外在C#中还提供了很多很多扩展方法来操作泛型集合,这里提一些常用的。

    //添加多个元素
    public void AddRange(IEnumerable<T> collection);
    
    //删除所有
    public void Clear();
    
    //按条件删除
    public int RemoveAll(Predicate<T> match);
    
    //按索引进行范围删除
    public void RemoveRange(int index, int count);
    
    //遍历操作
    public void ForEach(Action<T> action);
    
    //判断是否存在某元素
     public bool Contains(T item);
    
    //按条件判断是否存在
    public bool Exists(Predicate<T> match);
    
    //按条件查找指定元素
    public List<T> FindAll(Predicate<T> match);
    
    //翻转集合
    public void Reverse();
    
    //转换数组
    public T[] ToArray();
    

    2.Golang中的切片

    切片没有在C#中的泛型集合那么方便,具有一些硬性条件,例如分配空间,操作函数也少,但是也顺便减少了记忆量,记住下面的一些常规操作,基本就能看懂源码里对切片进行的相关操作。

    2.1 初始化-新增-复制

    //定义不初始化-这个定义不初始化的称为-零值切片
    var citySlice0 []string
    
    //定义且初始化
    var citySlice1 = []string{}
    var citySlice2 = []string{"北京", "上海", "广州", "深圳"}
    
    //make定义并初始化
    citySlice := make([]string, 4, 10)
    fmt.Printf("the citySlice is %v
    ", citySlice)
    //输出容量和长度
    fmt.Printf("the capacity of citySlice is %v,and the length of citySlice is %v 
    ", cap(citySlice), len(citySlice))
    
    //新增元素
    citySlice = append(citySlice, "北京", "上海", "广州", "深圳")
    fmt.Printf("the citySlice is %v
    ", citySlice)
    fmt.Printf("the capacity of citySlice is %v,and the length of citySlice is %v 
    ", cap(citySlice), len(citySlice))
    
    //新增元素
    citySlice = append(citySlice, "成都", "武汉")
    fmt.Printf("the citySlice is %v
    ", citySlice)
    fmt.Printf("the capacity of citySlice is %v,and the length of citySlice is %v 
    ", cap(citySlice), len(citySlice))
    
    //var声明的零值切片最简单的方式便是通过append函数直接使用,无需初始化
    var intSliceA []int
    intSliceA = append(intSliceA, 1, 2, 3)
    fmt.Printf("the intSliceA is %v 
    ", intSliceA)//[1 2 3]
    
    //切片是引用类型 简单的赋值就出现如下结果
    intSliceB := intSliceA
    intSliceB[0] = 0
    fmt.Printf("the intSliceA is %v 
    ", intSliceA) //[0,2,3]
    
    //为了不影响赋值操作,只要复制切片才能达到预期的效果, 但是把一个切片复制给另一个切片,目的切片需要分配空间
    intSliceC := make([]int, 4, 5)
    copy(intSliceC, intSliceA)
    fmt.Printf("the intSliceC is %v 
    ", intSliceC) //[0 2 3 0]  第4个元素0,是因为分配了空间,都是零值
    intSliceC[0] = 10
    fmt.Printf("the intSliceA is %v 
    ", intSliceA) //[0 2 3]
    fmt.Printf("the intSliceC is %v 
    ", intSliceC)	//[10 2 3 0]
    
    the citySlice is [   ]
    the capacity of citySlice is 10,and the length of citySlice is 4 
    the citySlice is [    北京 上海 广州 深圳]
    the capacity of citySlice is 10,and the length of citySlice is 8
    the citySlice is [    北京 上海 广州 深圳 成都 武汉]
    the capacity of citySlice is 10,and the length of citySlice is 10
    
    the intSliceA is [1 2 3]
    the intSliceA is [0 2 3]
    the intSliceC is [0 2 3 0]
    the intSliceA is [0 2 3]
    the intSliceC is [10 2 3 0]
    

    2.2 切

    切片之所以叫切片,着重点在切

    “数组上切,就成了切片,在切片上切,就成了切切片(#.#),当然不是,还是叫切片。”

    //the intSliceC is [10 2 3 0]
    
    //从索引1切到最后
    intSliceD := intSliceC[1:]
    fmt.Printf("the intSliceD is %v 
    ", intSliceD) // [2 3 0]
    
    //从索引1切到索引2,按照数学知识就是左闭右开[1,3)
    intSliceE := intSliceC[1:3]
    fmt.Printf("the intSliceE is %v 
    ", intSliceE) //[2 3]
    
    //从索引0切到n-1  0,1,2
    intSliceF := intSliceC[:3]
    fmt.Printf("the intSliceF is %v 
    ", intSliceF) //[10 2 3] 
    
    //再次验证长度与容量
    fmt.Printf("the capacity of intSliceF is %v,and the length of intSliceF is %v 
    ", cap(intSliceF), len(intSliceF))
    
    //
    fmt.Printf("the intSliceC is %v 
    ", intSliceC)	//[10 2 3 0]
    
    the intSliceD is [2 3 0]
    the intSliceE is [2 3]
    the intSliceF is [10 2 3] 
    the capacity of intSliceF is 5,and the length of intSliceF is 3
    the intSliceC is [10 2 3 0]
    

    2.3 删除

    golang是没有提供切片的直接删除函数,但是是可以利用内置的append()函数

    func append(slice []Type, elems ...Type) []Type
    

    ps:参数中使用可变参数... Type,是类似于C#中可变参数params T[] xC#内部是转换成数组处理,Golang内部转换为了切片。有那么一点差别,就是如果参数传切片,后面需要加...,其余用法与C#一致

    intSliceC = append(intSliceC[:1], intSliceC[2:]...) 
    fmt.Printf("the intSliceC is %v 
    ", intSliceC) // [10 2 0]
    fmt.Printf("the capacity of intSliceC is %v,and the length of intSliceC is %v 
    ", cap(intSliceC), len(intSliceC))
    
    the intSliceC is [10 2 0]
    the capacity of intSliceC is 5,and the length of intSliceC is 3
    

    2.4 判断切片是否为空

    只能使用len函数,不能使用nil

    len(s) == 0
    

    2.5 遍历

    s := []int{1, 3, 5}
    
    for i := 0; i < len(s); i++ {
        fmt.Println(i, s[i])
    }
    for index, value := range s {
        fmt.Println(index, value)
    }
    
    0 1
    1 3
    2 5
    0 1
    1 3
    2 5
    

    再次强调:这个系列并不是教程,如果想系统的学习,博主可推荐学习资源。

  • 相关阅读:
    [转]HD钱包的助记词与密钥生成原理
    [转]简单科普私钥、地址、助记词、Keystore的区别
    [转]Sequelize 中文API文档-4. 查询与原始查询
    [转]Node.JS使用Sequelize操作MySQL
    [转]OmniLayer / omnicore API 中文版
    [转]usdt omnicore testnet 测试网络
    [转]USDT与omniCore钱包
    [转]BTC RPC API GetTransaction
    [转]比特币测试链——Testnet介绍
    [转]BTC手续费计算,如何设置手续费
  • 原文地址:https://www.cnblogs.com/RandyField/p/14023587.html
Copyright © 2020-2023  润新知