


Go Slices and Subslices: Understanding Shared Memory and Avoiding `append()` Pitfalls
trap append()
Hi everyone! Welcome to my blog. ? If you are here, you may have just come into contact with Golang, or you are an experienced developer, and you want to understand the internal working principle of the section. So let's start!
GO language is highly praised because of its simplicity and efficiency -as people often say, "the GO language is to complete the work." For developers from C, C or Java and other languages, the simple grammar and ease of use of Go language are refreshing. However, even in the Go language, some characteristics may confuse developers, especially when processing slices and sub -slices. Let's unveil these subtleties and better understand how to avoid common traps of
and sliced to share memory.
append()
Usually, when you need a data structure to store a series of values, slicing is the first choice in Go language. Their flexibility comes from such a fact: their length is not part of its type. This feature overcomes the restrictions of the array, enabling us to create a single function that can handle any slices and enables the slice to increase or expand according to needs. Although the slice has some similarities with the array, such as both indexing and length, they have different data management methods. Slice acts as a reference to the underlying array, which actually stores the data of slices. In essence, the slice provides a view of some or all elements of the array. Therefore, when you create a slice, Go will automatically process the bottom array of creating sliced elements/data.
The shared memory of sliced
The array is a continuous memory block, but what makes the slice interesting is how they quote this memory. Let's break down the structure of the slice:
When you create a slice, it contains three components:
Poems pointing to the underlying array
type slice struct { array unsafe.Pointer // 指向底层数组的指针 len int // 切片中的元素数量 cap int // 底层数组的容量 }
<切> The length of the slicing (the number of elements it contains)
- <量> Capacity (the number of elements it can contain before the need to increase)
- This is where things become interesting. If you have multiple slices that are derived from the same array, changes made by a slice will be reflected in other slices because they share the same underlying array.
len
Let's see the following example: -
cap
<解> Understand slicing capacity
Before we further deepen, let's try to understand the slicing capacity
. When you get sub -slices from the existing Go language slicing, the
capacitypackage main import "fmt" func main() { // 创建一个具有初始值的切片 original := []int{1, 2, 3, 4, 5} // 创建一个子切片——两个切片共享相同的底层数组! subslice := original[1:3] fmt.Println("未修改的子切片:", subslice) // 输出 => 未修改的子切片: [2 3] // 修改子切片 subslice[0] = 42 fmt.Println("原始切片:", original) // 输出 => 原始切片: [1 42 3 4 5] fmt.Println("修改后的子切片:", subslice) // 输出 => 修改后的子切片: [42 3] }
When you create slices from arrays, the length of the slice is the number of elements it originally contained, and its capacity is the total number of elements that it can contain before it needs to grow.
Get sub -slicing
When you get the sub -slicing from the existing slices:
- The length is the number of elements you specified.
- <量> Capacity Calculated the capacity of the original slice minus the starting index of sub -slices.
type slice struct { array unsafe.Pointer // 指向底层数组的指针 len int // 切片中的元素数量 cap int // 底层数组的容量 }
- The original slice has 5 elements, and the length and capacity are 5.
- When you use <时>, it points to the elements from index 1 to 3 (2, 3, 4).
-
subslice := original[1:4]
<<> The length - is 4-1 = 3.
subslice
<<> The capacity is 5-1 = 4, because it starts from index 1 and includes elements to the end of the original slice. -
subslice
<<> Trap! <<>
Unused capacity sharing append()
The
of the sub -slicing includes elements that do not belong to their length but located in the original slicing capacity range. This means that if sub -slices increase, it can access or modify these elements. append()
<初> Initially pointing to 2, 3, the capacity is 4 (it can grow to the end of the original slice).
When you add 60, 70 to <追>, it uses the surplus capacity of the original slice.<<> and
package main import "fmt" func main() { // 创建一个具有初始值的切片 original := []int{1, 2, 3, 4, 5} // 创建一个子切片——两个切片共享相同的底层数组! subslice := original[1:3] fmt.Println("未修改的子切片:", subslice) // 输出 => 未修改的子切片: [2 3] // 修改子切片 subslice[0] = 42 fmt.Println("原始切片:", original) // 输出 => 原始切片: [1 42 3 4 5] fmt.Println("修改后的子切片:", subslice) // 输出 => 修改后的子切片: [42 3] }
-
subslice
Are you surprised? The operation modified the original slice because there is enough capacity in the underlying array. However, if we exceed the scope of capacity or additional elements exceeding the capacity permit, Go will allocate a new array for sub -sections to break the sharing with the original slicing: -
subslice
In this case, - created a new underlying array because the original capacity has exceeded.
original
subslice
<免> The best practice of avoiding traps
append()
<确> Clarify the capacity
func main() { // 原始切片 original := []int{1, 2, 3, 4, 5} // 创建一个子切片 subslice := original[1:4] // 指向元素 2, 3, 4 fmt.Println("子切片:", subslice) // 输出 => 子切片: [2 3 4] fmt.Println("子切片的长度:", len(subslice)) // 输出 => 子切片的长度: 3 fmt.Println("子切片的容量:", cap(subslice)) // 输出 => 子切片的容量: 4 }
append()
i. <建> Create a new slice with its own independent underlying array. This is important -it is not just a new section head, but a brand new array in the memory.
II. <然后> Then only transmit the value instead of memory reference. This is like a copy of a file instead of sharing the original file.- <完> Use the complete slice expression
func main() { original := []int{1, 2, 3, 4, 5} subslice := original[1:3] // 指向元素 2, 3 fmt.Println("追加前原始切片:", original) // 输出 => [1 2 3 4 5] fmt.Println("追加前子切片:", subslice) // 输出 => [2 3] fmt.Println("子切片的容量:", cap(subslice)) // 输出 => 4 // 在容量范围内追加到子切片 subslice = append(subslice, 60, 70) // 追加到子切片后打印 fmt.Println("追加后原始切片:", original) // 输出 => [1 2 3 60 70] fmt.Println("追加后子切片:", subslice) // 输出 => [2 3 60 70] }
<将> When passing the slice to a function that should not modify the original data, consider non -variability
make([]int, len(subslice))
copy()
The main advantage is:
- i. Data protection: The original data remains unchanged, prevent accidents and side effects
-
II. Predicate behavior: The effect of the function on the input does not hide
III. Parallel security: During the processing process, the original data can be used safely in other goroutine
<住> Remember:
- Slice is a reference to the underlying array
- Sub -slicing and parental sharing memory
- <创> Whether the creation of a new underlying array depends on the capacity
-
append()
When adding elements of sub -slicing elements with capacity, it will modify the data of the parent slicing. - When you want to avoid sharing, please use explicit memory management
- When processing sub -slices, please perform any of the following operations:
type slice struct { array unsafe.Pointer // 指向底层数组的指针 len int // 切片中的元素数量 cap int // 底层数组的容量 }
Copy after loginCopy after loginCopy after login
Do you think this resource is helpful? Do you have any questions? Or did you find an error or typo? Please leave your feedback in the comments. Don't forget to share this resource with others who may benefit from it. Follow me to get more information.
The above is the detailed content of Go Slices and Subslices: Understanding Shared Memory and Avoiding `append()` Pitfalls. For more information, please follow other related articles on the PHP Chinese website!

Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

Hot Topics

OpenSSL, as an open source library widely used in secure communications, provides encryption algorithms, keys and certificate management functions. However, there are some known security vulnerabilities in its historical version, some of which are extremely harmful. This article will focus on common vulnerabilities and response measures for OpenSSL in Debian systems. DebianOpenSSL known vulnerabilities: OpenSSL has experienced several serious vulnerabilities, such as: Heart Bleeding Vulnerability (CVE-2014-0160): This vulnerability affects OpenSSL 1.0.1 to 1.0.1f and 1.0.2 to 1.0.2 beta versions. An attacker can use this vulnerability to unauthorized read sensitive information on the server, including encryption keys, etc.

Backend learning path: The exploration journey from front-end to back-end As a back-end beginner who transforms from front-end development, you already have the foundation of nodejs,...

The library used for floating-point number operation in Go language introduces how to ensure the accuracy is...

Queue threading problem in Go crawler Colly explores the problem of using the Colly crawler library in Go language, developers often encounter problems with threads and request queues. �...

Under the BeegoORM framework, how to specify the database associated with the model? Many Beego projects require multiple databases to be operated simultaneously. When using Beego...

The difference between string printing in Go language: The difference in the effect of using Println and string() functions is in Go...

The problem of using RedisStream to implement message queues in Go language is using Go language and Redis...

What should I do if the custom structure labels in GoLand are not displayed? When using GoLand for Go language development, many developers will encounter custom structure tags...
