zhcn 编程语言 Golang Golang 介绍 非公開: Go语言切片详解

Go语言切片详解

切片是一种引用类型(即类似于 C/C++ 中的数组类型或 Python 中的列表类型),因为切片是对数组的连续段的引用,并且该段可以是完整的。由起始索引和结束索引标识的数组或多个项目的子集。请注意,由结束索引标识的项目不包含在切片中。

Go中切片的内部结构包括地址、大小和容量。切片通常用于快速操作部分数据收集。如果将数据收集比作切蛋糕,那么每一片都是您需要的“部分”。切割过程包括从哪里开始切割(切片起始位置)和切割多远(切片大小)。容量可以理解为切片口袋的大小,如下图所示。

[标题id =“attachment_1356”对齐=“aligncenter”宽度=“1024”] 图:Slice结构和内存分配图:Slice结构和内存分配[/caption]

从数组或切片生成新切片

默认情况下,切片指的是内存的连续区域。这可能是一个数组或一个切片本身。

从内存的连续区域生成切片是一种常见的操作,其格式为:

slice [開始位置 : 終了位置]

语法解释如下:

  • Slice:目标切片对象。
  • 起始位置:目标切片对象对应的索引。
  • 结束位置:对应于目标切片的结束索引。

以下是从数组生成切片的代码:

 var a[3]int{1, 2, 3}
fmt.Println(a, a[1:2]) 

这里,a是一个包含三个整数元素的数组,初始化为1到3之间的值,a[1:2]可用于生成新的切片。代码操作的结果是:

[1 2 3]  [2]

这里,[2]是[1:2]切片操作的结果。

从数组或切片创建新切片具有以下特征:

  • 要提取的元素数量是结束位置减去开始位置。
  • 检索到的元素不包含结束位置对应的索引,使用slice[len(slice)]检索切片的最后一个元素;
  • 默认起始位置是从连续区域的开头到结束位置。
  • 如果使用默认结束位置,则表示从开始位置到整个连续区域的结束位置。
  • 如果两者同时设置为默认值,则它相当于切片本身。
  • 如果两者同时为0,则相当于一个空切片,常用来重置切片。

根据索引位置获取切片元素的值时,取值范围为(0~len(slice)-1),超过限制会报运行时错误。生成切片时,可以指定结束位置。 len(slice) 但没有报错。

下面通过例子来了解切片的特性。

1)从指定范围生成切片

切片和数组是密不可分的。如果把阵列理解为办公楼,切片就是将不同的连续楼层出租给用户。租赁过程要求您选择起始楼层和结束楼层。这个过程产生切片。示例代码如下。

 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]) 

这是代码输出:

[11 12 13 14 15]
[21 22 23 24 25 26 27 28 29 30]
[1 2]

代码中,正在建设一栋30层的高层建筑,数组元素值范围为1到30,代表不同的独立楼层,输出结果是不同的出租和销售计划。

代码说明如下:

  • 8号线,我们正在尝试出租一个区域楼层。
  • 11 号线 20 层或以上的出租物业。
  • 14号二楼以下出租,一般为商业用途。

切片类似于 C 中的指针。指针可用于计算,但代价是内存操作越界。切片的大小根据指针增长,限制了切片对应的内存区域。使用切片时,切片内的地址和大小无法更改。切片比指针更安全、更稳健,因为它们是手动调整的。

2) 代表原始切片

在生成的切片的格式中,如果忽略起始位置和结束位置,则生成的切片表示与原始切片相同的切片,并且生成的切片在数据内容上也与原始切片匹配。像这样:

 a := []int{1, 2, 3}
fmt.Println(a[:])

a 是一个包含三个元素的切片。用a[:]操作切片a后,结果切片与切片a匹配。这是代码输出:

[1 2 3]

3)重置切片并清除拥有的元素

如果切片的起始位置和结束位置都设置为0,则生成的切片将为空。这是代码:

 a := []int{1, 2, 3}
fmt.Println(a[0:0])

a := []int{1, 2, 3}
fmt.Println(a[0:0]) 

这是代码输出:

[]

直接声明一个新的切片

除了从原始数组或切片生成切片之外,您还可以声明新切片。每个类型还可以有一个切片类型,表示相同类型的元素的连续集合,因此您也可以声明切片类型。切片类型的声明格式为:

var name []Type

其中,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)
fmt.Println(numList == nil)
fmt.Println(numListEmpty == nil) 

代码输出结果:

[] [] []
0 0 0
true
true
false

代码说明如下:

  • 第 2 行声明一个包含多个字符串的字符串切片。
  • 第 5 行声明一个包含多个整数值的整数切片。
  • 第 8 行将 numListEmpty 声明为整数切片。这将填充{}内切片的初始化元素,但由于此处没有填充,因此切片将为空。 然而,此时numListEmpty有分配给它的内存,但没有内存。元素仍然存在。
  • 第 11 行中,任何切片中都没有元素,并且所有三个切片的输出元素内容均为空。
  • 第14行,没有对切片进行任何操作,strList和numList没有指向数组或其他切片。
  • 在第 17 行和第 18 行中,已声明但未使用的切片的默认值为 nil,strList 和 numList 也为 nil,因此与 nil 的比较结果为 true。
  • 在第 19 行中,分配了 numListEmpty,但没有元素,因此将其与 nil 比较结果为 false。

切片是动态结构,只能确定是否等于 nil,而不能确定彼此是否相等。声明新切片后,您可以使用append()函数向切片添加元素。

使用 make() 函数构建切片

如果需要动态创建切片,可以使用内置函数make()。格式为:

make( []Type, size, cap )

其中,Type是指切片的元素类型,size是指分配给该类型的元素数量,cap是预先分配的元素数量。设置该值后,不会影响大小,但可以预先分配空间,以降低因多次分配而出现性能问题的风险。

一个例子是:

 a := make([]int, 2)
b := make([]int, 2, 10)

fmt.Println(a, b)
fmt.Println(len(a), len(b)) 

这是代码输出:

[0 0] [0 0]
2 2

a和b都是预分配的具有两个元素的切片,但是b的内部存储空间分配了10个切片,但实际上使用了两个元素。

容量不会影响当前的元素数量,因此a和b的len都是2。

善意的提示

使用make()函数生成的切片需要内存分配操作,但指定起始和结束位置的切片(包括重置切片)无需使用新的切片结构分配内存,只需指向该区域并设置起始和结束位置即可。 。不执行任何内存分配操作。

《Go语言切片详解》浅显易懂的讲解!您必须观看的最佳 2 个视频

【たった1時間で学べる】Go言語のプログラミング初心者向けの超入門講座【文字書き起こし、ソースコードも完全無料!】
https://www.youtube.com/watch?v=kPXfMFJ0oIE&pp=ygUtIEdv6KiA6Kqe44K544Op44Kk44K544Gu6Kmz44GX44GE6Kqs5piOJmhsPUpB
Go で配列とスライスを学ぶ | GoLang チュートリアル
https://www.youtube.com/watch?v=AxaeOSo9Y_c&pp=ugMICgJqYRABGAHKBS0gR2_oqIDoqp7jgrnjg6njgqTjgrnjga7oqbPjgZfjgYToqzmmI4maGw9SkE%3D
切片是一种引用类型(即类似于 C/C++ 中的数组类型或 Python 中的列表类型),因为切片是对数组的连续段的引用,并且该段可以是完整的。由起始索引和结束索引标识的数组或多个项目的子集。请注意,由结束索引标识的项目不包含在切片中。

Go中切片的内部结构包括地址、大小和容量。切片通常用于快速操作部分数据收集。如果将数据收集比作切蛋糕,那么每一片都是您需要的“部分”。切割过程包括从哪里开始切割(切片起始位置)和切割多远(切片大小)。容量可以理解为切片口袋的大小,如下图所示。

[标题id =“attachment_1356”对齐=“aligncenter”宽度=“1024”] 图:Slice结构和内存分配图:Slice结构和内存分配[/caption]

从数组或切片生成新切片

默认情况下,切片指的是内存的连续区域。这可能是一个数组或一个切片本身。

从内存的连续区域生成切片是一种常见的操作,其格式为:

slice [開始位置 : 終了位置]

语法解释如下:

  • Slice:目标切片对象。
  • 起始位置:目标切片对象对应的索引。
  • 结束位置:对应于目标切片的结束索引。

以下是从数组生成切片的代码:

 var a[3]int{1, 2, 3}
fmt.Println(a, a[1:2]) 

这里,a是一个包含三个整数元素的数组,初始化为1到3之间的值,a[1:2]可用于生成新的切片。代码操作的结果是:

[1 2 3]  [2]

这里,[2]是[1:2]切片操作的结果。

从数组或切片创建新切片具有以下特征:

  • 要提取的元素数量是结束位置减去开始位置。
  • 检索到的元素不包含结束位置对应的索引,使用slice[len(slice)]检索切片的最后一个元素;
  • 默认起始位置是从连续区域的开头到结束位置。
  • 如果使用默认结束位置,则表示从开始位置到整个连续区域的结束位置。
  • 如果两者同时设置为默认值,则它相当于切片本身。
  • 如果两者同时为0,则相当于一个空切片,常用来重置切片。

根据索引位置获取切片元素的值时,取值范围为(0~len(slice)-1),超过限制会报运行时错误。生成切片时,可以指定结束位置。 len(slice) 但没有报错。

下面通过例子来了解切片的特性。

1)从指定范围生成切片

切片和数组是密不可分的。如果把阵列理解为办公楼,切片就是将不同的连续楼层出租给用户。租赁过程要求您选择起始楼层和结束楼层。这个过程产生切片。示例代码如下。

 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]) 

这是代码输出:

[11 12 13 14 15]
[21 22 23 24 25 26 27 28 29 30]
[1 2]

代码中,正在建设一栋30层的高层建筑,数组元素值范围为1到30,代表不同的独立楼层,输出结果是不同的出租和销售计划。

代码说明如下:

  • 8号线,我们正在尝试出租一个区域楼层。
  • 11 号线 20 层或以上的出租物业。
  • 14号二楼以下出租,一般为商业用途。

切片类似于 C 中的指针。指针可用于计算,但代价是内存操作越界。切片的大小根据指针增长,限制了切片对应的内存区域。使用切片时,切片内的地址和大小无法更改。切片比指针更安全、更稳健,因为它们是手动调整的。

2) 代表原始切片

在生成的切片的格式中,如果忽略起始位置和结束位置,则生成的切片表示与原始切片相同的切片,并且生成的切片在数据内容上也与原始切片匹配。像这样:

 a := []int{1, 2, 3}
fmt.Println(a[:])

a 是一个包含三个元素的切片。用a[:]操作切片a后,结果切片与切片a匹配。这是代码输出:

[1 2 3]

3)重置切片并清除拥有的元素

如果切片的起始位置和结束位置都设置为0,则生成的切片将为空。这是代码:

 a := []int{1, 2, 3}
fmt.Println(a[0:0])

a := []int{1, 2, 3}
fmt.Println(a[0:0]) 

这是代码输出:

[]

直接声明一个新的切片

除了从原始数组或切片生成切片之外,您还可以声明新切片。每个类型还可以有一个切片类型,表示相同类型的元素的连续集合,因此您也可以声明切片类型。切片类型的声明格式为:

var name []Type

其中,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)
fmt.Println(numList == nil)
fmt.Println(numListEmpty == nil) 

代码输出结果:

[] [] []
0 0 0
true
true
false

代码说明如下:

  • 第 2 行声明一个包含多个字符串的字符串切片。
  • 第 5 行声明一个包含多个整数值的整数切片。
  • 第 8 行将 numListEmpty 声明为整数切片。这将填充{}内切片的初始化元素,但由于此处没有填充,因此切片将为空。 然而,此时numListEmpty有分配给它的内存,但没有内存。元素仍然存在。
  • 第 11 行中,任何切片中都没有元素,并且所有三个切片的输出元素内容均为空。
  • 第14行,没有对切片进行任何操作,strList和numList没有指向数组或其他切片。
  • 在第 17 行和第 18 行中,已声明但未使用的切片的默认值为 nil,strList 和 numList 也为 nil,因此与 nil 的比较结果为 true。
  • 在第 19 行中,分配了 numListEmpty,但没有元素,因此将其与 nil 比较结果为 false。

切片是动态结构,只能确定是否等于 nil,而不能确定彼此是否相等。声明新切片后,您可以使用append()函数向切片添加元素。

使用 make() 函数构建切片

如果需要动态创建切片,可以使用内置函数make()。格式为:

make( []Type, size, cap )

其中,Type是指切片的元素类型,size是指分配给该类型的元素数量,cap是预先分配的元素数量。设置该值后,不会影响大小,但可以预先分配空间,以降低因多次分配而出现性能问题的风险。

一个例子是:

 a := make([]int, 2)
b := make([]int, 2, 10)

fmt.Println(a, b)
fmt.Println(len(a), len(b)) 

这是代码输出:

[0 0] [0 0]
2 2

a和b都是预分配的具有两个元素的切片,但是b的内部存储空间分配了10个切片,但实际上使用了两个元素。

容量不会影响当前的元素数量,因此a和b的len都是2。

善意的提示

使用make()函数生成的切片需要内存分配操作,但指定起始和结束位置的切片(包括重置切片)无需使用新的切片结构分配内存,只需指向该区域并设置起始和结束位置即可。 。不执行任何内存分配操作。

《Go语言切片详解》浅显易懂的讲解!您必须观看的最佳 2 个视频

【たった1時間で学べる】Go言語のプログラミング初心者向けの超入門講座【文字書き起こし、ソースコードも完全無料!】
https://www.youtube.com/watch?v=kPXfMFJ0oIE&pp=ygUtIEdv6KiA6Kqe44K544Op44Kk44K544Gu6Kmz44GX44GE6Kqs5piOJmhsPUpB
Go で配列とスライスを学ぶ | GoLang チュートリアル
https://www.youtube.com/watch?v=AxaeOSo9Y_c&pp=ugMICgJqYRABGAHKBS0gR2_oqIDoqp7jgrnjg6njgqTjgrnjga7oqbPjgZfjgYToqzmmI4maGw9SkE%3D