Golang学习笔记之切片(slice)

切片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,以便释放内存。

4、如果两个切片共享同一块地址空间,使用append删除其中一个的参数,另一个切片虽然会被影响,但len不变,会自动在最后补上len长度的参数

demo

func main() {
    a1 := []int{1, 2, 3, 4, 5}
    a2 := a1
    a1 = append(a1[:2], a1[3:]...)
    fmt.Println(a1) //[1 2 4 5]
    fmt.Println(a2) //[1 2 4 5 5]
}
下面是整个例子
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]

}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,099评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,828评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,540评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,848评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,971评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,132评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,193评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,934评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,376评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,687评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,846评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,537评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,175评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,887评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,134评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,674评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,741评论 2 351

推荐阅读更多精彩内容

  • 线性结构是计算机最常用的数据结构之一。无论是数组(arrary)还是链表(list),在编程中不可或缺。golan...
    _二少爷阅读 6,600评论 5 13
  • Go 语言中,slice表示一个拥有相同类型元素的可变长度序列。slice通常被写为[]T,其中元素的类型都是T;...
    副班长国伟阅读 1,552评论 0 1
  • 1.安装 https://studygolang.com/dl 2.使用vscode编辑器安装go插件 3.go语...
    go含羞草阅读 1,548评论 0 6
  • 你的世界,我来过…… 如果当初没有相遇,或许我不会是现在的我,在你的世界里,我笑过,痛过....... 如今,满身...
    coiky阅读 263评论 0 0
  • 一. “你想猎谁啊”,这是我看到她的网名时脑海里迸出来的想法。 她微信昵称叫hunter,我知道这个,却也只知道这...
    49c9760681e2阅读 487评论 0 0