• golang切片


    切片与数组

    go的数组是这样的

    array := [3]int{1,2,3}
    array := [...]int{1,2,3}
    

    go的切片

    array := []int{1,2,3} //1
    array := make([]int,2) //2
    arr := [5]int{1,2,3,4,5}
    array :=arr[1:3] //底层数组可见 会修改原数组
    

    len和cap的区别

    make切片有两个参数lencap

    len:代表底层数组可访问的范围 用索引访问不可越过这个界限

    cap:代表底层数组的长度,如果append元素时没有超过这个cap,则不再创建底层数组,否则开辟新的空间,同时增大cap(这里有一个增大规则),所以如果适当设置大一些的cap还是能减少开销的

    array := make([]int,2,5) //len=2 cap=5
    array := make([]int,2) //make([]int,2,2)
    
    arr = [9]int{1,2,3,4,5,6,7,8,9}
    arr2 :=arr[2:5:6]  //长度为 5-2  容量为6-2
    

    切片传参

    func Args(arr ...int){
        
    } 
    Args(1,2,3,4,5)
    

    这里arr的类型就是切片类型


    切片的底层结构

    runtime/slice.go

    type slice struct {
    	array unsafe.Pointer
    	len   int
    	cap   int
    }
    unsafe.Pointer其实就是*int类型 指向内存地址
    

    切片为什么是引用类型?

    切片传入函数,同样也是值传递,会copy一份切片的值传入函数内,哪为什么又说是引用类型呢?为什么函数内部改变会影响原切片呢?

    根据上面的切片底层结构我们知道,切片有一个指向底层数组的指针,虽然切片是传值复制了一份,同时指向底层数组的指针也复制了一份,但指针始终是指向同一个地址的,那么我们改变切片的值其实就是改变底层数组的值。因为他们还是共享底层地址的。


    遍历切片的优化

    我们知道,切片可以用range遍历

    	//耗时  因为要建立新的变量
    	for _,v:=range arrStr{
    		log.Println("执行操作:",v)
    	}
    

    下面做一些优化,忽略值,而是用索引来,这样就不用再开辟空间创建一个变量并且赋值给变量了

    //优化
    	arrStr:=[]string{"a","b","c","d"}
    	for key:=range arrStr{
    		log.Println("[优化]执行操作:",arrStr[key])
    	}
    

    空切片的判断

    空切片可以判断它的长度是否为0,但是判断为nil来判断这个切片是否为空是不准确的,

    比如下面两种情况就要用len是否为0来判断:

    empty1:=make([]int,0)
    log.Println(empty1==nil) //false
    empty1=[]int{}
    log.Println(empty1==nil)
    

    下面的就是为nil 因为这只是声明,而没有开辟地址

    var empty2 []int
    log.Println(empty2==nil)  //true
    

    切片的克隆

    刚学习go切片的新手可能会进行最简单的操作

     a := []int{1, 2, 3}
     b := make([]int, len(a)) //使用copy函数必须复制切片的结构必须和源数据结构一致
     copy(b, a)
    

    上面的操作进行了很多不必要的工作,开辟空间等等...让代码看起来不是很简洁,内存也有一定开销,当然这里影响很小,再看如下的clone

    arrStr:=[]string{"a","b","c","d"}
    arrStrClone:=append(arrStr[:0:0],arrStr...)
    

    这个操作笔者以前也没见过,但是看了大佬的书籍才学会的这种骚操作,代码很简洁

    删除切片的元素

    删除一段切片,如下,删除了 [1-3) 的元素,删除后为[a,d,e,f] 注意是前闭后开

    arrStrClone=[]string{"a","b","c","d","e","f"}
    arrStrClone = append(arrStrClone[:1], arrStrClone[3:]...)
    

    删除一个元素

    其实是删除一段元素的特例,这里就不举例了

    切片的插入

    如何在切片中插入切片呢?或者在切片中插入元素呢?

    其实和删除的思想是一样的

    // Push(插入到结尾)
    s = append(s, elements...)
    // Unshift(插入到开头)
    s = append(elements, s...)
    
    //将切片elements的元素插入到s切片的i位置之后
    s = append(s[:i], append(elements, s[i:]...)...)
    

    切片实现栈队列

    s, e = s[1:], s[0]  //shift操作 将开头元素弹出
    s, e = s[:len(s)-1], s[len(s)-1] //pop 将尾元素弹出
    

    // Push(插入到结尾)
    s = append(s, elements...)
    // Unshift(插入到开头)
    s = append(elements, s...)
    

    关于并发

    注意,go里面的特殊容器都是现成不安全的,多个并发读取可以,但是并发修改是不允许的

  • 相关阅读:
    python常见报错解释
    selenium键盘操作
    html常用属性,标签,选择器
    模块(三)
    类的继承
    java接口
    java新建文件夹中的绝对路径和相对路径的理解以及中文乱码问题
    Java IO
    JS中的排序算法(-)冒泡排序
    CSS+DIV布局中absolute和relative的区别
  • 原文地址:https://www.cnblogs.com/biningooginind/p/12436756.html
Copyright © 2020-2023  润新知