Go语言之切片Slice练习

切片Slice理论知识

  • 其本身并不是数组,它指向底层的数组
  • 作为编程数组的替代方案,可以关联底层数组的局部或者全部
  • 为引用类型
  • 可以直接创建或从底层数组获取生成
  • 使用len()获取元素个数,cap()获取容量
  • 一般使用make()创建
  • 如果多个slice指向相同底层数组,其中一个的值改变会影响全部
  • make([]T, len, cap)
  • 其中,cap可以省略,则和len的值相同
  • len表示存数的元素个数,cap表示容量

slice与底层数组的关系

Reslice

  • Reslice时索引以被slice的切片为准
  • 索引不可以超过被slice的切片的容量cap()的值
  • 索引越界不会导致底层数组的重新分配而是引发错误

Append

  • 可以在slice尾部追加元素
  • 可以将一个slice追加在另一个slice尾部
  • 如果最终长度未超过追加到slice的容量则返回原始slice
  • 如果超过追加到的slice的容量则将重新分配数组并拷贝原始数据

Copy

//切片slice  练习
package main

import "fmt"

func main() {
    //============先创建一个数组====
    // 创建数组,必须指明个数
    age := [4]int{}
    fmt.Println(age)

    //=========声明一个切片Slice类型=====
    // 看见了吧,切片类型,是不需要指明 个数的
    // 记住,slice类型的底层,也是数组
    var s1 []float64
    fmt.Println(s1)

    //========方式一:利用已有的数组,来初始化s1
    sparkNodeCpu := [...]float64{4.5, 3.4, 2.3, 9.8, 10}
    s1 = sparkNodeCpu[3:5] //从下标为3的元素,开始获取
    fmt.Println("------------->\t", s1)
    s1 = sparkNodeCpu[1:] //从下标为1的元素,获取到 最后
    fmt.Println(s1)

    s1 = sparkNodeCpu[:4] //指定最后一个获取的元素
    fmt.Println(s1)

    //========方式二:利用make关键字,来创建切片
    //make([]T, len, cap)
    //[]T,表示切片的类型
    //len,表示当前元素的个数,或者,初始化的个数
    //cap,由于切片的底层其实是数组,而数组在内存里是一块连续的空间,
    //      如make([]int, 3,10)  为了提升效率,一般先在内存里创建
    // 一块连续的内存大小,为10,如果你的元素个数超过了10的话,
    //Go语言,会默认将你现在的内存空间,由10,增加到20,重新在内存里找一块连续的空间,分配20个空间
    // 如果又超过20的话,就分配40,就这么下去。因此,最好你知道你需要多大的内存空间
    s2 := make([]int, 3, 10)
    fmt.Println(len(s2), cap(s2)) // 3  10

    s2a := make([]int, 3)           // 也可以不指定cap,这样的话,cap的默认值,就是len的长度
    fmt.Println(len(s2a), cap(s2a)) // 3  3

    //=======================Reslice========练习=====
    // 先声明一个切片类型
    a := []rune{‘a‘, ‘b‘, ‘c‘, ‘d‘, ‘e‘, ‘f‘, ‘j‘, ‘k‘, ‘u‘}

    //以原切片a为基础,开始切
    //此时,你要注意了,新产生的切片s3的容量
    //下面的操作就是Reslice
    s3 := a[2:5] //表示,从下标为2开始,到5结束,最大不能超过被切slice的cap容量7
    s3a := s3[3:5]

    fmt.Println("长度:\t", len(s3), "\t容量cap:\t", cap(s3))   //3 7
    fmt.Println("长度:\t", len(s3a), "\t容量cap:\t", cap(s3a)) //2 4
    fmt.Println(string(s3a))

    //=======================Append========练习=====
    slice1 := make([]int, 3, 6)                   //默认值是全是0
    fmt.Printf("先打印出slice1的内存地址:\t %p\n", slice1) // 0xc042078090

    //先追加3个元素
    slice1 = append(slice1, 1, 3, 5)

    //再打印出slice1的值,和 内存地址
    fmt.Printf("%v  %p\n", slice1, slice1) //[0 0 0 1 3 5]  0xc042078090

    //继续追加元素,查看,内存地址,是否发生了变化
    slice1 = append(slice1, 4, 5, 6)

    // 超过了slice1的容量后,重新分配了内存地址
    fmt.Printf("%v  %p\n", slice1, slice1) //[0 0 0 1 3 5 4 5 6]  0xc042056060

    fmt.Println("=======================================")
    //测试,当多个切片都指向同一个底层数组时,并且多个切片有共同的元素时,如果其中一个元素,发生变化的话,
    //其他切片也会发生变化的
    appleSlice := []int{3, 4, 5, 9, 8, 7}
    bananaS := appleSlice[3:6]
    orangeS := appleSlice[2:5]

    //bananaS  orangeS  有两个共同的元素
    fmt.Println(appleSlice) //[3 4 5 9 8 7]
    fmt.Println(bananaS)    //[9 8 7]
    fmt.Println(orangeS)    //[5 9 8]

    fmt.Println("=======================================")
    //假设bananaS切片里的元素,第1个元素,发生了变化的话,
    //测试,appleSlice,orangeS 是否也发生了变呢
    //我改动的是下标为1,值为8的元素,将8改为了110,与此同时,其他切片中,8的值也全都改成了110了
    bananaS[1] = 110        //将下标为1的元素,设置为110
    fmt.Println(appleSlice) //[3 4 5 9 110 7]
    fmt.Println(bananaS)    //[9 110 7]
    fmt.Println(orangeS)    //[5 9 110]

    fmt.Println("=======================================")
    // 注意,此时,orangeS,orangeS 依旧都执行底层的数组appleSlice
    //还要注意下面的情形
    //利用Append方法
    bananaS = append(
        bananaS, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7)
    //此时,bananaS已经不再指向appleSlice了,因为超过了appleSlice的容量

    //而是,指向了新的地址,此时,我们再修改bananaS
    bananaS[1] = 1110

    fmt.Println(appleSlice) //[3 4 5 9 110 7]
    //看见了把,仅仅是修改了自己的值,appleSlice,orangeS 并没有发生变化
    fmt.Println(bananaS) //[9 1110 7 7 7 7 7 7 7 7 7 7 7 7 7 7]
    fmt.Println(orangeS) //[5 9 110]

    fmt.Println("=======================================")
    //=======================Copy========练习=====
    // copy(A,B) 是说,将B里的元素,拷贝到A里
    ftpNum := []int{4, 6, 7, 2, 3, 8, 9}
    sftpNum := []int{1, 2, 3}
    //将sftp
    copy(ftpNum, sftpNum) //注意,copy之后,就会将原先的值该了
    fmt.Println(ftpNum)
    fmt.Println(sftpNum)

    //截取拷贝
    copy(sftpNum[1:2], ftpNum[2:3])
    fmt.Println(ftpNum)
    fmt.Println(sftpNum)

}

原文地址:http://blog.51cto.com/xingej/2097563

时间: 2024-07-31 19:32:29

Go语言之切片Slice练习的相关文章

【Go语言】【7】GO语言的切片

如果说GO语言的数组为静态长度的数组,那么切片(slice)则为动态长度的数组 一.基于数组创建切片 1.存在一个整型数组intArr := [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10},那么下面的slice就是数组切片 var slice []int = intArr[3:7] 从图中可以看出切片从数组的第4个元素开始读取数据,直至第8个元素(但不包含第8个).切记程序员的计数都是从0开始的哟 2.若只读intArr数组的前4个元素,该如何办呢?聪明的你一定能想

Go语言数组,切片

数组声明 Go 语言数组声明需要指定元素类型及元素个数,语法格式如下: var variable_name [SIZE] variable_type 以上为一维数组的定义方式.数组长度必须是整数且大于 0.例如以下定义了数组 balance 长度为 10 类型为 float32: var balance [10] float32 初始化数组 以下演示了数组初始化: var balance = [5]float32{1000.0, 2.0, 3.4, 7.0, 50.0} 初始化数组中 {} 中的

Go语言之切片

切片也是一种数据结构,它和数组非常相似,因为他是围绕动态数组的概念设计的,可以按需自动改变大小,使用这种结构,可以更方便地管理和使用数据集合. 内部实现 切片是基于数组实现的,它的底层是数组,它自己本身非常小,可以理解为对底层数组的抽象.因为机遇数组实现,所以它的底层的内存是连续非配的,效率非常高.它还有可以通过索引获得数据.可以迭代以及垃圾回收优化的好处. 切片对象非常小,是因为它是只有 3 个字段的数据结构:一个是指向底层数组的指针,一个是切片的长度,一个是切片的容量.这 3 个字段,就是G

Go语言的切片

Go 语言切片(Slice) Go 语言切片是对数组的抽象. Go 数组的长度不可改变,在特定场景中这样的集合就不太适用,Go中提供了一种灵活,功能强悍的内置类型切片("动态数组"),与数组相比切片的长度是不固定的,可以追加元素,在追加时可能使切片的容量增大. 定义切片 你可以声明一个未指定大小的数组来定义切片: var identifier []type 切片不需要说明长度. 或使用make()函数来创建切片: var slice1 = make([] type, len) 或者写成

Go 灵活多变的切片Slice

我们知道数组定义好之后其长度就无法再修改,但是,在实际开发过程中,有时候我们并不知道需要多大的数组,我们期望数组的长度是可变的, 在 Go 中有一种数据结构切片(Slice) 解决了这个问题,它是可变长的,可以随时向Slice 里面添加数据. 1 什么是切片(Slice) 在 Go 源码中是这样定义切片的,源码地址:https://github.com/golang/go/blob/master/src/runtime/slice.go type slice struct { array uns

Golang 入门 : 切片(slice)

切片(slice)是 Golang 中一种比较特殊的数据结构,这种数据结构更便于使用和管理数据集合.切片是围绕动态数组的概念构建的,可以按需自动增长和缩小.切片的动态增长是通过内置函数 append() 来实现的,这个函数可以快速且高效地增长切片,也可以通过对切片再次切割,缩小一个切片的大小.因为切片的底层也是在连续的内存块中分配的,所以切片还能获得索引.迭代以及为垃圾回收优化的好处.本文将介绍 Golang 切片的基本概念和用法,演示环境为 ubuntu 18.04 & go1.10.1. 切

golang切片slice

切片slice是引用类型 len()函数获取元素的个数 cap()获取数组的容量 1.申明方式 (1)var a []int 与数组不同的是他不申明长度(2)s2 := make([]int, 3, 10) //元素的类型,元素的数量,元素的容量  fmt.Println(len(s2), cap(s2)) 输出元素的数量和容量 2.讲数组转换成切片 2 a := [10]int{} 3 fmt.Println(a) 4 s1 := a[:10] //取前10个元素 [5:]取 5-最后的元素

(一)Python入门-2编程基本概念:16字符串-切片slice操作-逆序

一:字符串切片slice操作 切片 slice 操作可以让我们快速的提取子字符串.标准格式为: [起始偏移量start:终止偏移量end:步长 step] 典型操作(三个量为正数的情况)如下: 操作和说明 示例 结果 [:] 提取整个字符串 “abcdef”[:] “abcdef” [start:]从start 索引开始到结尾 “abcdef”[2:] “cdef” [:end]从头开始直到end-1 “abcdef”[:2] “ab” [start:end]从start 到 end-1  “a

数组array和切片(slice)的区别

一 数组简介: 数组是内置(build-in)类型,是一组同类型数据的集合,它是值类型,通过从0开始的下标索引访问元素值.在初始化后长度是固定的,无法修改其长度.当作为方法的参数传入时将复制一份数组而不是引用同一指针.数组的长度也是其类型的一部分,通过内置函数len(array)获取其长度.注意:和C中的数组相比,又是有一些不同的 1. Go中的数组是值类型,换句话说,如果你将一个数组赋值给另外一个数组,那么,实际上就是将整个数组拷贝一份2. 如果Go中的数组作为函数的参数,那么实际传递的参数是