Golang学习笔记之切片(slice)

栏目: Go · 发布时间: 7年前

内容简介:• 引⽤类型。但⾃⾝是结构体,值拷⻉传递。• 属性 len 表⽰可⽤元素数量,读写操作不能超过该限制。• 属性 cap 表⽰最⼤扩张容量,不能超出数组限制。

切片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)》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

The Master Switch

The Master Switch

Tim Wu / Knopf / 2010-11-2 / USD 27.95

In this age of an open Internet, it is easy to forget that every American information industry, beginning with the telephone, has eventually been taken captive by some ruthless monopoly or cartel. Wit......一起来看看 《The Master Switch》 这本书的介绍吧!

URL 编码/解码
URL 编码/解码

URL 编码/解码

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具