gopointersslice

How to understand slices in structs in Golang


I'm new to Golang and I'm trying to understand pointers

type deque struct {
    indexes []int
}

func (d *deque) push(i int) {
    d.indexes = append(d.indexes, i)
}

the indexes here is a slice instead of a pointer to a slice.
how is the indexes actually stored in memory ?

for example: when we initiate an instance of deque, let's call it dq, in memory, dq's address is 0x1001(let's call it adr(dq)).

what is the variable stored in adr(dq)?, is it an pointer to an array?

0x1001 -> Ox8009(the address to the first element of array)

or is it the array it self?
0x1001 -> first element of the slice
0x1002 -> second element of the slice

and what happens when we :

d.indexes = append(d.indexes, i)

and what's the difference if we define:

type deque struct {
    indexes *[]int
}

Solution

  • For example, the address of the instance of deque in memory is 0x1001. It initializes:

    0x1001 -> [indexes: nil]
    

    If you add a new element (dq.push(12)):

    0x1001 -> [length: 1, capacity: 1, data: 0x3001 (pointer to data)]
    0x3001 -> [12]
    

    The slice structure at 0x1001 contains information about the length and capacity of the slice (length: 1, capacity: 1), and the actual data is stored at another address (let's say 0x3001, array [12]).

    If you push other elements (dq.push(34), dq.push(56)).

    0x1001 -> [length: 3, capacity: 4, data: 0x5001 (new pointer to data due to capacity, capacity doubles)]
    0x5001 -> [12, 34, 56]
    

    Code1:

    type deque struct {
        indexes []int
    }
    func (d *deque) push(i int) {
        d.indexes = append(d.indexes, i)
    }
    func main() {
        dq := deque{}
        dq.push(12)
        dq.push(34)
        dq.push(56)
        fmt.Println("Deque elements:", dq.indexes)
    }
    

    Output1:

    Deque elements: [12 34 56]
    

    If a pointer to a slice (*[]int) is used instead of the slice itself ([]int). It means that the indexes field will hold a pointer to a slice, and it needs to initialize this pointer before using it.

    If you add a new element (dq.push(12)), 0x2001 is the address of the underlying slice structure pointed to by indexes

    0x1001 -> [indexes: 0x2001 (pointer to slice)]
    0x2001 -> [length: 1, capacity: 1, data: 0x3001 (pointer to data)]
    0x3001 -> [12]
    

    The slice structure at 0x2001 contains information about the length and capacity of the slice (length: 1, capacity: 1), and the actual data is stored at another address (0x3001, array [12]).

    If you push other elements (dq.push(34), dq.push(56)).

    0x1001 -> [indexes: 0x2001 (pointer to slice)]
    0x2001 -> [length: 3, capacity: 4, data: 0x5001 (new data pointer, due to capacity, capacity doubles)]
    0x5001 -> [12, 34, 56]
    

    Code2:

    type deque struct {
        indexes *[]int
    }
    
    func (d *deque) push(i int) {
        if d.indexes == nil {    // initialize the slice if it's nil
            d.indexes = &[]int{}
        }
        *d.indexes = append(*d.indexes, i)
    }
    
    func main() {
        dq := deque{}
        dq.push(12)
        dq.push(34)
        dq.push(56)
        fmt.Println("Deque elements:", *dq.indexes)
    }
    

    Output2:

    Deque elements: [12 34 56]