美文网首页程序员Golang
Golang学习笔记之切片(slice)

Golang学习笔记之切片(slice)

作者: 学生黄哲 | 来源:发表于2018-12-05 17:58 被阅读68次

    切片slice:切片是对数组的抽象。切片在内存中占24个字节

    runtime.h
    struct Slice{      // must not move anything
        byte* array;   // actual data
        uintgo len;    // number of elements
        uintgo cap;    // allocated number of elements
    };
    

    切片包含长度、容量、以及一个指向首元素的指针

    • 引⽤类型。但⾃⾝是结构体,值拷⻉传递。
    • 属性 len 表⽰可⽤元素数量,读写操作不能超过该限制。
    • 属性 cap 表⽰最⼤扩张容量,不能超出数组限制。
    • 如果 slice == nil,那么 len、 cap 结果都等于 0。
    • 作为变长数组的替代方案,可以关联底层数组的局部或全部
    •可以直接创建或从底层数组获取生成
    • 使用len()获取元素个数,cap()获取容量
    • 一般使用make()创建
    •如果多个slice指向相同底层数组,其中一个值的改变会影响全部
    •在通过下标访问元素时下标不能超过len大小,如同数组的下标不能超出len范围一样。

    make([]T, len, cap)
    其中cap可以省略,则和len的值相同
    len表示存放的元素个数,cap表示容量

    1、初始化的几种方式

        //第一种方式创建切片
        var slice []int
        fmt.Println(len(slice)) //0
    
        //第二种方式
        sl1 := []int{0, 1, 2, 3, 8: 100}     // 通过初始化表达式构造,可使⽤索引号。
        fmt.Println(sl1, len(sl1), cap(sl1)) //[0 1 2 3 0 0 0 0 100] 9 9
    
        sl2 := make([]int, 10) // 使⽤ make 创建,省略 cap,相当于 cap = len。
        fmt.Println(sl2)       //[0 0 0 0 0 0 0 0 0 0]
    
        //第三种方式
        num := []int{10, 20, 30, 40, 50}
        fmt.Println(num) //[10 20 30 40 50]
    

    2、append

    向 slice 尾部添加数据,返回新的 slice 对象
    切片可以通过内置函数append(slice []Type,elems …Type)追加元素,elems可以是一排type类型的数据,也可以是slice,因为追加的一个一个的元素,因此如果将一个slice追加到另一个slice中需要带上”…”,这样才能表示是将slice中的元素依次追加到另一个slice中。append追加元素超出实际容量会执行扩容,会扩展为slice原先容量的2倍
    (1)//将一个slice追加到另一个slice中需要带上”…”,这样表示是将slice中的元素依次追加到另一个slice中
    例:

        veggies := []string{"potatoes", "tomatoes", "brinjal"}
        fruits := []string{"oranges", "apples"}
        food := append(veggies, fruits...) //veggies+fruits
        fmt.Println("food:", food)
    

    (2)切片元素删除,可以使用append来实现
    s = append(s[:i], s[i+1:]…)
    首先s[:i]相当于slice截取,也就是说s[:i]本身就是一个slice。然后s[i+1:]…相当于变长参数。使用append的特性(向 slice 尾部添加数据,返回新的 slice 对象)来实现删除的功能。可以单个也可以删除多个。
    例:

        //删除scile中元素,删除下标为2的元素
        test := []int{10, 20, 30, 40, 50, 100}
        test = append(test[:2], test[3:]...)
        fmt.Println(test) //[10 20 40 50 100]
    

    3、copy

    函数 copy 在两个 slice 间复制数据,复制⻓度以 len ⼩的为准。两个 slice 可指向同⼀底层数组,允许元素区间重叠。
    例:

        //copy
        countries := []string{"USA", "Singapore", "Germany", "India", "Australia"}
        neededCountries := countries[:len(countries)-2]
        countriesCpy := make([]string, len(neededCountries))
        copy(countriesCpy, neededCountries)
        fmt.Println(countriesCpy)
        fmt.Println(len(countriesCpy), cap(countriesCpy))
        
        data := [...]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
        s := data[8:]
        s2 := data[:5]
        copy(s2, s)       // dst:s2, src:s
        fmt.Println(s2)   //[8 9 2 3 4]
        fmt.Println(data) //[8 9 2 3 4 5 6 7 8 9]
    

    应及时将所需数据 copy 到较⼩的 slice,以便释放内存。

    下面是整个例子
    package main
    
    import (
        "fmt"
        "unsafe"
    )
    
    func main() {
        //第一种方式创建切片
        var slice []int
        fmt.Println(len(slice)) //0
    
        //第二种方式
        sl1 := []int{0, 1, 2, 3, 8: 100}     // 通过初始化表达式构造,可使⽤索引号。
        fmt.Println(sl1, len(sl1), cap(sl1)) //[0 1 2 3 0 0 0 0 100] 9 9
    
        sl2 := make([]int, 10) // 使⽤ make 创建,省略 cap,相当于 cap = len。
        fmt.Println(sl2)       //[0 0 0 0 0 0 0 0 0 0]
    
        //第三种方式
        num := []int{10, 20, 30, 40, 50}
        fmt.Println(num) //[10 20 30 40 50]
    
        fmt.Printf("type is %T\tsize is %d\n", sl2, unsafe.Sizeof(sl2))
    
        var b []int
        b = num[1:4] //左闭右开从num下标1到3
        var b1 []int
        b1 = num[:] //num的全部
        fmt.Println(b)
        fmt.Println(b1)
        
    
        //切片为数组的引用
        darr := [...]int{57, 89, 90, 82, 100, 78, 67, 69, 59}
        dslice := darr[2:5]
        fmt.Println("array before", darr)
        for i := range dslice {
            dslice[i]++
        }
        fmt.Println("array after", darr)
    
        //切片指向数组,容量cap会从strartIndex取到数组结束,长度是指定截取长度
        fruitarray := [...]string{"apple", "orange", "grape", "mango", "water melon",
            "pine apple", "chikoo"}
        fruitslice := fruitarray[0:3]
        //长度2容量6
        fmt.Printf("length of slice %d capacity %d", len(fruitslice), cap(fruitslice))
    
        //append追加元素超出实际容量会执行扩容,会扩展为原先容量的2倍
        slice1 := make([]int, 5, 10)
        fmt.Println(slice1)
        slice3 := append(slice1, 1, 2, 3, 4, 5)
        fmt.Println(slice3)
    
        //执行append会会返回一个新的数值可以用原切片接收也可以使用别的
        var slice4 []int //空的切片初始为nil
        fmt.Println(slice4)
        if slice4 == nil {
            slice4 = append(slice4, 1, 2, 3, 4)
            fmt.Println(slice4)
        }
    
        //将一个slice追加到另一个slice中需要带上"…",这样表示是将slice中的元素依次追加到另一个slice中
        veggies := []string{"potatoes", "tomatoes", "brinjal"}
        fruits := []string{"oranges", "apples"}
        food := append(veggies, fruits...) //veggies+fruits
        fmt.Println("food:", food)
    
        //二维切片,每一行元素的个数可以不一致
        pls := [][]string{
            {"C", "C++"},
            {"JavaScript"},
            {"Go", "Rust"},
        }
        fmt.Println(len(pls), cap(pls)) //长度为3容量为3
        for _, v1 := range pls {
            for _, v2 := range v1 {
                fmt.Printf("%s ", v2)
            }
            fmt.Printf("\n")
        }
    
        //copy
        countries := []string{"USA", "Singapore", "Germany", "India", "Australia"}
        neededCountries := countries[:len(countries)-2]
        countriesCpy := make([]string, len(neededCountries))
        copy(countriesCpy, neededCountries)
        fmt.Println(countriesCpy)
        fmt.Println(len(countriesCpy), cap(countriesCpy))
    
        data := [...]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
        s := data[8:]
        s2 := data[:5]
        copy(s2, s)       // dst:s2, src:s
        fmt.Println(s2)   //[8 9 2 3 4]
        fmt.Println(data) //[8 9 2 3 4 5 6 7 8 9]
    
        //删除scile中元素,删除下标为2的元素
        test := []int{10, 20, 30, 40, 50, 100}
        test = append(test[:2], test[3:]...)
        fmt.Println(test) //[10 20 40 50 100]
    
    }
    

    相关文章

      网友评论

        本文标题:Golang学习笔记之切片(slice)

        本文链接:https://www.haomeiwen.com/subject/nypwcqtx.html