Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert slice of string to slice of pointer to string

I want to convert a slice of string into slice of pointer to string

values1 := []string{"a", "b", "c"}
var values2 []*string
for _, v := range values1 {
    fmt.Printf("%p | %T\n", v, v)
    values2 = append(values2, &v)
}
fmt.Println(values2)

%!p(string=a) => string
%!p(string=b) => string
%!p(string=c) => string
[0xc42000e1d0 0xc42000e1d0 0xc42000e1d0]

From my understanding,
My variable v seems to be a string, not a pointer to string.
Therefore v should be copied from values1 when iterating.

Obviously I'm incorrect as v still have the same address 0xc42000e1d0.
How can v value change if it's not a pointer?

For a quick solution use:

values1 := []string{"a", "b", "c"}
var values2 []*string
for i, _ := range values1 {
    values2 = append(values2, &values1[i])
}
like image 339
Martin Magakian Avatar asked Mar 07 '23 01:03

Martin Magakian


1 Answers

The first version doesn't work as there is only one loop variable v, which has the same address in each iteration. The loop variable is assigned in each iteration, which changes its value but not its address, and you append this same address in each iteration.

A possible solution is what you proposed: to append the address of the proper slice element of the original slice:

for i := range values1 {
    values2 = append(values2, &values1[i])
}

This works, but note that values2 contains addresses pointing to the backing array of values1, so the backing array of values1 will be kept in memory (will not get garbage collected) until both values1 and values2 variables are unreachable. Also note that modifying elements of values1 will effect values2 indirectly, because elements of values2 point to elements of values1.

Another solution is to create temporary local variables and append the addresses of those:

for _, v := range values1 {
    v2 := v
    values2 = append(values2, &v2)
}

By doing this, your values2 slice will not keep values1 from getting garbage collected, also modifying values in values1 will not be reflected in values2, they will be independent.

See related questions about the loop variable:

Why do these two for loop variations give me different behavior?

Golang: Register multiple routes using range for loop slices/map

like image 182
icza Avatar answered Mar 17 '23 00:03

icza