zoukankan      html  css  js  c++  java
  • 切片 Slice

    切片,并不是数组或数组指针,它通过内部指针和相关属性引用数组片段,以实现变长方案。

    1. 切片是数组的一个引用,因此切片是引用类型,但自身是结构体,值拷贝传递
    2. 切片的长度是可以改变的,因此,切片是一个可变的数组
    3. 切片的遍历方式和数组一样,可以用len()求长度,表示可用元素数量,读写操作不能超过该限制
    4. cap可以求出slice最大的扩张容量,不能超出数组限制,0 <= len(slice) <= len(array)
    5. 定义:var 变量名 []类型
    6. 如果 slice == nil,那么 len,cap 结果都是 0

    创建切片的几种方式:

    package main
     
    import (
        "fmt"
    )
     
    func main() {
     
    	var s1 []int					// 声明
    	s2 := []int{}					// 声明+赋值,赋值为空
    	var s3 []int = make([]int,5)	// len = cap = 5
    	var s4 []int = make([]int,2,5)	// type len cap
    	s5 := []int{1,2,3}				// 声明+赋值
    
    	arr := [5]int{1,2,3,4,5}		// 对数组进行切片
    	var s6 []int
    	s6 = arr[1:4]
    
    }
    

      

    切片初始化

    package main
    
    import (
        "fmt"
    )
    
    var arr = [...]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
    var slice0 []int = arr[2:8]
    var slice1 []int = arr[0:6]        //可以简写为 var slice []int = arr[:end]
    var slice2 []int = arr[5:10]       //可以简写为 var slice[]int = arr[start:]
    var slice3 []int = arr[0:len(arr)] //var slice []int = arr[:]
    var slice4 = arr[:len(arr)-1]      //去掉切片的最后一个元素
    
    func main() {
    
        arr2 := [...]int{9, 8, 7, 6, 5, 4, 3, 2, 1, 0}
        slice5 := arr[2:8]
        slice6 := arr[0:6]         //可以简写为 slice := arr[:end]
        slice7 := arr[5:10]        //可以简写为 slice := arr[start:]
        slice8 := arr[0:len(arr)]  //slice := arr[:]
        slice9 := arr[:len(arr)-1] //去掉切片的最后一个元素
    
    }
    

      

    通过make,创建切片

    package main
    
    import (
        "fmt"
    )
    
    // 全局
    var slice0 []int = make([]int,5)		// [0 0 0 0 0]
    var slice1 = make([]int,5)				// [0 0 0 0 0]
    var slice2 = make([]int,2,5)			// [0 0]
    
    func main() {
    
    	// 局部
    	slice3 := make([]int,5)				// [0 0 0 0 0]
    	slice4 := make([]int,2,5)			// [0 0]
    
    }
    

      

    读写操作,实际目标是底层数组,只需要注意索引的差别

    package main
    
    import (
        "fmt"
    )
    
    func main() {
    
    	data := [...]int{0,1,2,3,4,5}
    
    	s := data[2:4]
    	s[0] += 100
    	s[1] += 200
    
    	fmt.Println(s)			// [102 203]
    	fmt.Println(data)		// [0 1 102 203 4 5]
    
    }
    

      

    直接创建slice对象,自动分配底层数组

    package main
    
    import "fmt"
    
    func main() {
        s1 := []int{0, 1, 2, 3, 8: 100}			//	索引为8,共9个元素
        fmt.Println(s1, len(s1), cap(s1))		//	[0 1 2 3 0 0 0 0 100] 9 9
    
        s2 := make([]int, 6, 8) 				//	len = 6 , cap = 8
        fmt.Println(s2, len(s2), cap(s2))		//	[0 0 0 0 0 0] 6 8
    
        s3 := make([]int, 6) 					//	len = cap = 6
        fmt.Println(s3, len(s3), cap(s3))		//	[0 0 0 0 0 0] 6 6
    }
    

     使用make动态创建slice,避免了数组必须用常量做长度的麻烦。还可以用指针直接访问底层数组,退化成普通数组操作。

    package main
    
    import "fmt"
    
    func main() {
    
    	s := []int{0,1,2,3}
    
    	p := &s[2]				// 获取数组元素的指针
    	*p += 100				// 重新赋值
    	
    	// s[2] += 100
    
    	fmt.Println(s)			// [0 1 102 3]
    
    }
    

      

    [][]T,是指 元素类型为 []T

    package main
    
    import "fmt"
    
    func main() {
    
    	data := [][]int{
    		[]int{1,2,3},
    		[]int{100,200},
    		[]int{11,22,33,44},
    	}
    	fmt.Println(data)    // [[1 2 3] [100 200] [11 22 33 44]]
    }

     直接修改 struct array/slice 成员

    package main
    
    import "fmt"
    
    func main() {
    
    	d := [5]struct{
    		x int
    	}{}
    
    	s := d[:]
    
    	d[1].x = 10
    	s[2].x = 20
    
    	fmt.Println(d)              // [{0} {10} {20} {0} {0}]
    	fmt.Printf("%p,%p,
    ",&d,&d[0])    // 0xc042066030,0xc042066030,
    
    }
    

      

    切片基本操作,增删改查

    package main
    
    import "fmt"
    
    func main() {
    
    	// 增
    	var a = []int{1,3,5}
    	var b = []int{2,4,6}
    	c := append(a,b...)			//	append 追加数据
    	fmt.Println(c)				//	[1 3 5 2 4 6]
    	d := append(c,9)
    	fmt.Println(d)				//	[1 3 5 2 4 6 9]
    
    	// 删  用append,以另一种形式实现删除操作
    	d = append(d[:3],d[4:]...)
    	fmt.Println(d)				// [1 3 5 4 6 9]	删除第四个元素
    
    	// 改
    	// 用append删除一个元素,再用append增加一个元素
    
    	// 查
    	fmt.Println(d[1:3])		// [3 5]
    
    	// 清空
    	d = nil
    	fmt.Println(d)			// []
    
    }
    

      

     向切片中添加元素,生成新切片

    package main
    
    import (
        "fmt"
    )
    
    func main() {
    
        s1 := make([]int, 0, 5)			
        fmt.Printf("%p
    ", &s1)			// 0xc0420443a0
    
        s2 := append(s1, 1)
        fmt.Printf("%p
    ", &s2)			// 0xc0420443e0
    
        fmt.Println(s1, s2)				// [] [1]
    
    }
    

      

     超出原切片cap限制,就会重新分配底层数组,即便原数组并未填满。

    package main
    
    import (
        "fmt"
    )
    
    func main() {
    
        data := [...]int{0, 1, 2, 3}
        s := data[:2:3]						// 取data前两个元素,并设置cap为3 
    
        s = append(s, 100, 200) 			// append 两个值,超出 s.cap 限制。重新分配底层数组,与原数组无关。
    
        fmt.Println(s, data)         		// [0 1 100 200] [0 1 2 3]
        fmt.Println(&s[0], &data[0]) 		// 比对底层数组起始指针。	0xc04200a270 0xc042008320
    
    }

    从输出结果可以看出,append后的s重新分配了底层数据,并复制数据。如果只追加一个值,则不会超过 s.cap 限制,也就不会重新分配。通常以2倍容量重新分配底层数组。

    在大批量添加数据时,建议一次性分配足够大的空间,以减少内存分配和数据复制的开销。或初始化足够长的len属性,改用索引号进行操作。及时释放不再使用的slice对象,避免持有过期数组,造成GC无法回收。

    slice中cap重新分配规律:以2倍容量进行重新分配

    package main
    
    import (
        "fmt"
    )
    
    func main() {
    
        s := make([]int, 0, 1)
    	c := cap(s)
    
        for i := 0; i < 50; i++ {
            s = append(s, i)
            if n := cap(s); n > c {
                fmt.Printf("cap: %d -> %d
    ", c, n)
                c = n
            }
        }
    
    }
    // cap: 1 -> 2
    // cap: 2 -> 4
    // cap: 4 -> 8
    // cap: 8 -> 16
    // cap: 16 -> 32
    // cap: 32 -> 64
    

      

     遍历

    package main
    
    import "fmt"
    
    func main() {
    
        data := []int{10, 20, 30, 40, 50, 60, 70, 80, 90}
        for index,val := range data {
            fmt.Println(index,val)
        }
    
    }
    

      

     调整大小

    package main
    
    import "fmt"
    
    func main() {
        var a = []int{1, 3, 4, 5}
        fmt.Printf("slice a : %v , len(a) : %v
    ", a, len(a))
        b := a[1:2]
        fmt.Printf("slice b : %v , len(b) : %v
    ", b, len(b))
        c := b[0:3]
        fmt.Printf("slice c : %v , len(c) : %v
    ", c, len(c))
    }
    // slice a : [1 3 4 5] , len(a) : 4
    // slice b : [3] ,       len(b) : 1
    // slice c : [3 4 5] ,   len(c) : 3
    

    数组与切片,内存分布

    字符串与切片

    package main
    
    import "fmt"
    
    func main() {
    
        str := "hello world"
    
        // 字符串切片
        s1 := str[:5]              
        fmt.Println(s1)
    
        // 字符串 修改
        s2 := []byte(str)       //中文字符需要用[]rune(str)
        s2[0] = 'H'
        s2 = append(s2,'!')
        s3 := string(s2)
        fmt.Println(s3)
    

      

     切片:的理解

    data[6:8],取6和7,长度len=2,最大可扩容长度cap=4

    data[:6:8],内容为0-5,长度len=6,cap=8

  • 相关阅读:
    接口测试--apipost中cookie管理器的使用
    python解释器换了路径,导致pip安装失败解决方法
    Jmeter之Bean shell使用(二)
    Jmeter之Bean shell使用(一)
    BeanShell生成随机数
    Jmeter之Json 提取器
    Jmeter全面信息学习笔记
    python模块之codecs
    open()和with open()的区别
    【图像处理】第二次实验:二维快速傅里叶变换与离散余弦变换
  • 原文地址:https://www.cnblogs.com/yizhixiaowenzi/p/14659104.html
Copyright © 2011-2022 走看看