5

Just so you know, I am quite new to Go.

I have been trying to make a function like this:

func PointersOf(slice []AnyType) []*AnyType{
    //create an slice of pointers to the elements of the slice parameter
}

It is like doing &slice[idx] for all elements in the slice, but I am having trouble with how to type my parameters and return type, as well as how to create the slice itself.

This method needs to work for slices of built-in types, as well as for slices of structs and slices of pointers to built-in types/structs

After invoking this function it would be preferable if I don't have to cast the pointer slice


Edit: The reason why I need this method is to have a generic way to use the elements of an array in a for ... range loop, in stead of using copies of that element. Consider:

type SomeStruct struct {
    x int
}

func main() {
    strSlice := make([]SomeStruct, 5)
    for _, elem := range strSlice {
        elem.x = 5
    }
}

This Doesn't work, because elem is a copy of the strSlice element.

type SomeStruct struct {
    x int
}

func main() {
    strSlice := make([]SomeStruct, 5)
    for _, elem := range PointersOf(strSlice) {
        (*elem).x = 5
    }
}

This however should work, since you only copy the pointer that points to an element in the original array.

6
  • 2
    You can't; Go types are invariant, and there are no generics. You create a slice of the type you need when you need it. Can you give an example why you would need this? Commented Jan 6, 2016 at 14:15
  • Perhaps you should first try to write such a function and make it work for a slice of integers only, for example. Then your AnyType should be an empty interface (interface{}) i guess, in case you want to support different types. Also can you show us a bit code, so that we can specifically help with what you're having problems. Commented Jan 6, 2016 at 14:20
  • I am trying to make this because the for ... range returns a copy of the elements in the given slice. If I want to change my elements I'd normally need to use a normal for loop and fetch the element from the index e = &slice[idx]. It would however be easier if I could get the pointer array and use the elements by reference Commented Jan 6, 2016 at 14:21
  • 1
    @coolcat007: this is why for ... range returns an index as the first parameter, so you can index into your slice instead of making a copy. play.golang.org/p/f5ZY3-npaB Commented Jan 6, 2016 at 14:29
  • 2
    Go strives to never have hidden complexity, and your conversion requires an extra allocation and an O(n) copy. If you need to have a pointer to a value, you should always start with a pointer, i.e. your slice should be []*SomeStruct from the start. Commented Jan 6, 2016 at 14:34

1 Answer 1

3

Use the following code to loop through a slice of structs setting a field. There's no need to create a slice of pointers.

type SomeStruct struct {
  x int
}

func main() {
  strSlice := make([]SomeStruct, 5)
  for i := range strSlice {
    strSlice[i].x = 5
  }
}

playground example

Here's the proposed PointersOf function:

func PointersOf(v interface{}) interface{} {
  in := reflect.ValueOf(v)
  out := reflect.MakeSlice(reflect.SliceOf(reflect.PtrTo(in.Type().Elem())), in.Len(), in.Len())
  for i := 0; i < in.Len(); i++ {
    out.Index(i).Set(in.Index(i).Addr())
  }
  return out.Interface()
}

and here's how to use it:

for _, elem := range PointersOf(strSlice).([]*SomeStruct) {
    elem.x = 5
}

playground example

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.