golang基础语法(五)切片

目录

一、什么是切片

1、从连续内存区域生成切片

2、从数组生成切片

二、直接声明新的切片

[1、append() 函数](#1、append() 函数)

[三、make() 函数构造切片](#三、make() 函数构造切片)

思考题

四、切片复制


一、什么是切片

切片(Slice)与数组一样,也是可以容纳若干类型相同的元素的容器。与数组不同的是,无法通过切片类型来确定其值的长度。

每个切片值都会将数组作为其底层数据结构。我们也把这样的数组称为切片的底层数组。

切片(slice)是对数组的一个连续片段的引用,所以切片是一个引用类型。

这个片段可以是整个数组,也可以是由起始和终止索引标识的一些项的子集,需要注意的是,终止索引标识的项不包括在切片内(左闭右开的区间)。

Go语言中切片的内部结构包含地址、大小和容量,切片一般用于快速地操作一块数据集合。

1、从连续内存区域生成切片

格式如下:

复制代码
slice [开始位置 : 结束位置]

语法说明如下:

  • slice:表示目标切片对象;
  • 开始位置:对应目标切片对象的索引;
  • 结束位置:对应目标切片的结束索引。

2、从数组生成切片

代码如下:

复制代码
var a  = [3]int{1, 2, 3}
//a[1:2] 生成了一个新的切片
fmt.Println(a, a[1:2]) //[1 2 3],[2]

从数组或切片生成新的切片拥有如下特性:

  • 取出的元素数量为:结束位置 - 开始位置;
  • 取出元素不包含结束位置对应的索引,切片最后一个元素使用 slice[len(slice)] 获取;
  • 当缺省开始位置时,表示从连续区域开头到结束位置(a[:2])
  • 当缺省结束位置时,表示从开始位置到整个连续区域末尾(a[0:])
  • 两者同时缺省时,与切片本身等效(a[:])
  • 两者同时为 0 时,等效于空切片,一般用于切片复位(a[0:0])

注意:超界会报运行时错误,比如数组长度为3,则结束位置最大只能为3

切片在指针的基础上增加了大小,约束了切片对应的内存区域,切片使用中无法对切片内部的地址和大小进行手动调整,因此切片比指针更安全、强大。

示例

复制代码
var highRiseBuilding [30]int
for i := 0; i < 30; i++ {
     highRiseBuilding[i] = i + 1
}
// 区间
fmt.Println(highRiseBuilding[10:15])
// 中间到尾部的所有元素
fmt.Println(highRiseBuilding[20:])
// 开头到中间指定位置的所有元素
fmt.Println(highRiseBuilding[:2])

二、直接声明新的切片

除了可以从原有的数组或者切片中生成切片外,也可以声明一个新的切片每一种类型都可以拥有其切片类型,表示多个相同类型元素的连续集合。

切片类型声明格式如下:

复制代码
//name 表示切片的变量名,Type 表示切片对应的元素类型。
var name []Type

// 声明字符串切片
var strList []string

// 声明整型切片
var numList []int

// 声明一个空切片
var numListEmpty = []int{} //赋了空值

// 输出3个切片
fmt.Println(strList, numList, numListEmpty)

// 输出3个切片大小
fmt.Println(len(strList), len(numList), len(numListEmpty))

// 切片判定空的结果
fmt.Println(strList == nil) //true
fmt.Println(numList == nil) //true
fmt.Println(numListEmpty == nil) //true

1、append() 函数

切片是动态结构,只能与 nil 判定相等,不能互相判定相等。声明新的切片后,可以使用 append() 函数向切片中添加元素

复制代码
    var strList []string
    // 追加一个元素
    strList = append(strList,"ms的go教程")
    fmt.Println(strList)

三、make() 函数构造切片

如果需要动态地创建一个切片,可以使用 make() 内建函数,格式如下:

复制代码
make( []Type, size, cap )
  • Type 是指切片的元素类型

  • size 指的是为这个类型已经被分配多少个元素

  • cap 为预分配的元素数量,这个值设定后不影响 size,只是能提前分配空间,降低多次分配空间造成的性能问题

    复制代码
      a := make([]int, 2)
      b := make([]int, 2, 10)
      fmt.Println(a, b)
      //容量不会影响当前的元素个数,因此 a 和 b 取 len 都是 2
      //但如果我们给a 追加一个 a的长度就会变为3
      a = append(a, 3)
      fmt.Println(len(a), len(b))

使用 make() 函数生成的切片一定发生了内存分配操作,但给定开始与结束位置(包括切片复位)的切片只是将新的切片结构指向已经分配好的内存区域,设定开始与结束位置,不会发生内存分配操作。

思考题

复制代码
 var numbers4 = [...]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
    myslice := numbers4[4:6]
    //这打印出来长度为2
    fmt.Printf("myslice为 %d, 其长度为: %d\n", myslice, len(myslice))
    myslice = myslice[:cap(myslice)]
    //为什么 myslice 的长度为2,却能访问到第四个元素
    fmt.Printf("myslice的第四个元素为: %d", myslice[3])
  1. 长度(len)​ ​:切片当前存储的元素个数(可通过 len(myslice)获取)

  2. ​容量(cap)​ ​:切片可以扩展到的最大长度(不重新分配内存的情况下,可通过 cap(myslice)获取)

四、切片复制

Go语言的内置函数 copy() 可以将一个数组切片复制到另一个数组切片中,如果加入的两个数组切片不一样大,就会按照其中较小的那个数组切片的元素个数进行复制。

copy() 函数的使用格式如下:

复制代码
copy( destSlice, srcSlice []T) int
  • 其中 srcSlice 为数据来源切片
  • destSlice 为复制的目标(也就是将 srcSlice 复制到 destSlice)

目标切片必须分配过空间且足够承载复制的元素个数,并且来源和目标的类型必须一致,copy() 函数的返回值表示实际发生复制的元素个数。

下面的代码展示了使用 copy() 函数将一个切片复制到另一个切片的过程:

复制代码
slice1 := []int{1, 2, 3, 4, 5}
slice2 := []int{5, 4, 3}
copy(slice2, slice1) // 只会复制slice1的前3个元素到slice2中
copy(slice1, slice2) // 只会复制slice2的3个元素到slice1的前3个位置

切片的引用和复制操作对切片元素的影响:

复制代码
package main
import "fmt"
func main() {
    // 设置元素数量为1000
    const elementCount = 1000
    // 预分配足够多的元素切片
    srcData := make([]int, elementCount)
    // 将切片赋值
    for i := 0; i < elementCount; i++ {
        srcData[i] = i
    }
    // 引用切片数据 切片不会因为等号操作进行元素的复制
    refData := srcData
    // 预分配足够多的元素切片
    copyData := make([]int, elementCount)
    // 将数据复制到新的切片空间中
    copy(copyData, srcData)
    // 修改原始数据的第一个元素
    srcData[0] = 999
    // 打印引用切片的第一个元素 引用数据的第一个元素将会发生变化
    fmt.Println(refData[0])
    // 打印复制切片的第一个和最后一个元素 由于数据是复制的,因此不会发生变化。
    fmt.Println(copyData[0], copyData[elementCount-1])
    // 复制原始数据从4到6(不包含)
    copy(copyData, srcData[4:6])
    for i := 0; i < 5; i++ {
        fmt.Printf("%d ", copyData[i])
    }
}
相关推荐
轩情吖2 小时前
Qt常用控件之QWidget(三)
开发语言·c++·qt·控件·cursor·qwidget·windowopacity
Yilena2 小时前
跟进 JDK25:将虚拟线程安全引入生产的权衡与实战
java·开发语言·虚拟线程·结构化并发·jdk25
_bong2 小时前
python的高阶函数
开发语言·python
MSTcheng.2 小时前
【C++】如何搞定 C++ 内存管理?
开发语言·c++·内存管理
钟离墨笺2 小时前
Go语言-->切片注意点及理解
java·开发语言·golang
余大侠在劈柴2 小时前
go语言学习记录9.23
开发语言·前端·学习·golang·go
麦麦鸡腿堡3 小时前
Java的数组查找
java·开发语言
Rsingstarzengjx3 小时前
【算法】【数学】【质数】质数相关 leetcode 204
数据结构·算法
一碗白开水一3 小时前
【第29话:路径规划】自动驾驶启发式搜索算法(A星搜索算法( A* 搜索算法))详解及代码举例说明
人工智能·算法·机器学习·计算机视觉·自动驾驶·unix