SoFunction
Updated on 2025-03-03

Detailed explanation of go slices and pointer slice examples

In Go, slices and slices of pointers (i.e. each element in a slice is a pointer to a certain data type) are two different concepts, each with specific uses and advantages.

Slice

A slice is a reference to a continuous fragment of an array, which provides an abstract representation of a collection of array elements. The underlying data structure of slices is an array, which contains three key parts: a pointer to the starting element of the array, a slice length, and a slice capacity. The slice length refers to the number of elements currently contained in the slice, and the slice capacity refers to the number of elements from the starting element of the slice to the last element of the bottom array.

An important feature of slices is that it provides a dynamic view of the underlying array. This means that you can access, modify, and manipulate some or all elements of an array through slices without copying the entire array. In addition, the slice can be easily expanded and reduced in size to meet the needs of different scenarios.

Example

package main  
import "fmt"  
func main() {  
    // Define an array    array := [5]int{1, 2, 3, 4, 5}  
    // Create a slice that references the first three elements of the array    slice := array[:3]  
    // Print slice elements    (slice) // Output: [1 2 3]    // Modifying the slice element will also modify the elements corresponding to the underlying array    slice[1] = 100  
    (array) // Output: [1 100 3 4 5]}

Slice of pointer

A slice of a pointer is a slice, but its element is a pointer pointing to an instance of a certain data type. This means that each element is an address through which the actual data can be accessed and manipulated indirectly. Slices of pointers are often used in scenarios where large amounts of data are required to store and want to avoid data replication, or when it is necessary to store variable-sized objects in slices.

Using slicing of pointers saves memory space because only pointers are stored instead of actual data. At the same time, the original data can be easily modified through pointers. However, this also brings additional complexity and risks, as the dereference and memory management of pointers need to be handled with care.

Example

package main  
import "fmt"  
type Person struct {  
    Name string  
    Age  int  
}  
func main() {  
    // Create pointers to several Person instances    person1 := &Person{Name: "Alice", Age: 30}  
    person2 := &Person{Name: "Bob", Age: 25}  
    // Create a slice of pointers to store these pointers    people := []*Person{person1, person2}  
    // Modify the properties of the Person instance through a pointer    people[0].Age = 31  
    // Print the modified Person instance    (people[0].Name, people[0].Age) // Output: Alice 31}

The difference between structure slice and structure pointer slice

  • Memory usage:

    • Structure slice: Each element is a complete copy of the structure, so it consumes a lot of memory.

    • Structure pointer slice: Each element is just a pointer to the structure, and the memory consumption is small. However, this does not mean that the overall memory footprint will be small, because the memory occupied by the actual structure object also needs to be considered.

  • Modify elements:

    • Structure slice: Modifying an element in the slice will directly modify the value of the element and will not affect other slices or original structure objects.

    • Structure pointer slice: Modify the element pointed to by a pointer in the slice, which will affect all pointers to that element. If multiple slices or variables point to the same structure object, modifying the content of that object will affect all references.

  • Initialization and assignment:

    • Structure slice: can be initialized and assigned directly.

    • Structure pointer slice: You need to initialize the structure object first, and then assign the address of the object to the slice.

  • nil with empty slices:

    • For structure pointer slices, nil slices and empty slices (slices of length 0) are different. The nil slice does not allocate the underlying array, while the empty slices allocate the underlying array but have a length of 0.

    • For structure slices, nil slices are not usually discussed because slices are always associated with the underlying array.

Can you directly traverse the structure slice and assign the value to the structure pointer slice

Cannot directly traverse the structure slice and assign value to the structure pointer slice. Because the elements in the structure slice are the values ​​of the structure, and the elements in the structure pointer slice are pointers to the structure. You need to traverse the struct slices and create pointers for each element separately, and then add these pointers to the struct pointer slice.

Example description

Suppose we have onePersonStructure:

type Person struct {  
    Name string  
    Age  int  
}

Use of structure slices

// Create and initialize a Person structure slicepeopleSlice := []Person{  
    {"Alice", 30},  
    {"Bob", 25},  
}  
// Modify an element in the slicepeopleSlice[0].Age = 31  
// traverse and print elements in the slicefor _, person := range peopleSlice {  
    (, )  
}

Use of structure pointer slices

// Create and initialize some Person structure objectsalice := Person{"Alice", 30}  
bob := Person{"Bob", 25}  
// Create a Person pointer slice and add the address of the structure object to the slicepeoplePtrSlice := []*Person{&alice, &bob}  
// Modify the element pointed to by a pointer in the slicepeoplePtrSlice[0].Age = 31 // This will change the age of alice, because peoplePtrSlice[0] points to alice// Iterate over and print elements in the slice (by dereference pointer)for _, personPtr := range peoplePtrSlice {  
    (, )  
}  
// If you want to traverse the structure slice and assign the value to the structure pointer slice, you need to do this:peopleSlice := []Person{  
    {"Charlie", 28},  
    {"David", 35},  
}  
// Initialize an empty Person pointer slice with the same length as peopleSlicepeoplePtrSlice = make([]*Person, len(peopleSlice))  
// traverse peopleSlice and assign a new pointer to peoplePtrSlicefor i, person := range peopleSlice {  
    // Create a copy of the person, get its address, and assign it to peoplePtrSlice    peoplePtrSlice[i] = &Person{Name: , Age: }  
}  
// NowpeoplePtrSliceIncludes pointingpeopleSlicePointer to the element copy

In the example above,peoplePtrSliceIt is through traversalpeopleSliceand create the address of each element's copy to initialize. If you wantpeoplePtrSlicePointer in pointer topeopleSliceThe same objects (not copies) you need to make sure that these objects are passednewFunction or through&Operators are allocated on the heap, and their addresses are added topeoplePtrSlicemiddle. However, in most cases, you may not want to do this, as this will result in sharing the same object between slices, which can cause unexpected side effects.

Can you directly traverse the structure pointer slice and assign value to the structure slice

You cannot directly traverse the structure pointer slice and assign value to the structure slice. The element in the structure pointer slice is a pointer to the structure, while the element in the structure slice is the value of the structure. So if you try to assign a pointer in the pointer slice directly to the structure slice, you will get the value of the pointer (i.e. the memory address), not the value of the structure object itself.

To traverse the structure pointer slice and assign the structure object pointed to by the pointer to the structure slice, you need to dereference each pointer, get the structure object it points to, and then assign the object to the corresponding position in the structure slice.

Here is a detailed example and analysis:

package main  
import (  
    "fmt"  
)  
// Define Person structuretype Person struct {  
    Name string  
    Age  int  
}  
func main() {  
    // Initialize some Person structure objects and get their addresses    alice := &Person{"Alice", 30}  
    bob := &Person{"Bob", 25}  
    // Create a Person pointer slice    peoplePtrSlice := []*Person{alice, bob}  
    // Create a Person structure slice with the same length as peoplePtrSlice    peopleSlice := make([]Person, len(peoplePtrSlice))  
    // traverse peoplePtrSlice, dereference pointer and assign structure objects to peopleSlice    for i, personPtr := range peoplePtrSlice {  
        peopleSlice[i] = *personPtr // Dereference pointer to get structure object    }  
    // Now peopleSlice contains a copy of the structure object pointed to by the pointer in peoplePtrSlice    (peopleSlice) // Output: [{Alice 30} {Bob 25}]    // Modifying elements in peopleSlice will not affect peoplePtrSlice or original structure objects    peopleSlice[0].Age = 31  
    (peopleSlice) // Output: [{Alice 31} {Bob 25}]    (peoplePtrSlice) // Output: [&{Alice 30} &{Bob 25}], the elements in peoplePtrSlice have not changed}

In this example:

  • We first created twoPersonPointer to structure objectaliceandbob
  • Then we create a containing both pointerspeoplePtrSliceslice.
  • Then we created apeoplePtrSliceThe same length is emptyPersonSlice structurepeopleSlice
  • On traversalpeoplePtrSliceWhen we use*personPtrto dereference pointer and assign the resulting structure object topeopleSlicecorresponding position in .
  • Finally, we verified the modificationpeopleSliceThe elements in it will not affectpeoplePtrSliceor original structure object.

It should be noted that doing so creates a copy of the structure object. If you just want to reference the original objects instead of their copy, you should use pointer slices directly instead of creating structure slices. If you really need structure slices,And want to keep a reference to the original object,Then you need to rethink your data structure design,Because the structure slice itself does not save references to the original object。

This is the end of this article about go slices and pointer slices. For more related go slices and pointer slices, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!