Range references instead values
PointersReferenceGoPointers Problem Overview
I saw that range returns the key and the "copy" of the value. Is there a way for that range to return the address of the item? Example
package main
import "fmt"
type MyType struct {
field string
}
func main() {
var array [10]MyType
for _, e := range array {
e.field = "foo"
}
for _, e := range array {
fmt.Println(e.field)
fmt.Println("--")
}
}
http://play.golang.org/p/AFOGG9NGpx
Here "field" is not modified because range sends the copy of field. Do I have to use index or is there any other way to modify the value?
Pointers Solutions
Solution 1 - Pointers
The short & direct answer: no, use the array index instead of the value
So the above code becomes:
package main
import "fmt"
type MyType struct {
field string
}
func main() {
var array [10]MyType
for idx, _ := range array {
array[idx].field = "foo"
}
for _, e := range array {
fmt.Println(e.field)
fmt.Println("--")
}
}
Solution 2 - Pointers
To combine @Dave C and @Sam Toliman's comments
package main
import "fmt"
type MyType struct {
field string
}
func main() {
var array [10]MyType
for idx := range array {
e := &array[idx]
e.field = "foo"
}
for _, e := range array {
fmt.Println(e.field)
fmt.Println("--")
}
}
Solution 3 - Pointers
Go's range
only supports assignment by value. There is no &range
because the problem it solves is too trivial.
The desired effect can be achieved as follows:
for i := range array {
e := &array[i]
e.field = "foo"
}
Solution 4 - Pointers
package main
import "fmt"
type MyType struct {
field string
}
func main() {
var array [10]MyType
for index, _ := range array {
array[index].field = "foo"
}
for _, e := range array {
fmt.Println(e.field)
fmt.Println("--")
}
}
Solution 5 - Pointers
type arrType []string
type refArrType []*string
func ref(arr arrType) refArrType {
refs := make(refArrType, len(arr))
for i := 0; i < len(arr); i++ {
refs[i] = &arr[i]
}
return refs
}
func main() {
arr := arrType{"hello", "world"}
for _, item := range ref(arr) {
*item = "some other string"
fmt.Println(item, arr)
}
}
I won't encourage to use this. But if you really want to iterate over items by references then you can make a new slice of refs (not best for space complexity) and loop over that.
But with that wherever you are assigning new value to item you'll have to dereference the pointer and use it (that is what makes it bad in my opinion). So yes I won't use this solution.
And also it works only for array of strings. You have to make new ref
function for other types :(
Solution 6 - Pointers
It's been said in the comments already, but for those looking for answers right away, here's how you can achieve expected result by using a slice of pointers and by making the least changes to the original code.
package main
import "fmt"
type MyType struct {
field string
}
func main() {
// Slice of pointers instead of slice of type
var array [10]*MyType
// Initialize array manually
for idx := range array {
array[idx] = &MyType{}
}
for _, e := range array {
e.field = "foo"
}
for _, e := range array {
fmt.Println(e.field)
fmt.Println("--")
}
}
Here it is in playground
Solution 7 - Pointers
package main
import "fmt"
type MyType struct {
field string
}
func main() {
var array [10]MyType
for index := range array {
array[index].field = "foo"
}
for _, e := range array {
fmt.Println(e.field)
fmt.Println("--")
}
}