Idiomatic way to initialize an array in a struct

11,068 views
Skip to first unread message

Matt Thiffault

unread,
Jun 11, 2011, 5:44:00 PM6/11/11
to golan...@googlegroups.com
Hello,

I am usually a C programmer, decided to play with go because I like the look of many of its features. Here is my question:

If I want to have a type with a member array, but I don't know how big I want that array to be until I instantiate/initialize the type, how do I go about this? I haven't managed to find anything in the docs pertaining to this.

For instance, in C:

struct MyStruct {

    // Use a pointer we can set to allocated memory later
    int* a;

}

void InitStruct(struct MyStruct* foo, int array_size){
   foo->a = malloc(array_size * sizeof(int))
}

...

struct MyStruct myinstace;

InitStruct(&myinstance);


I figure I could potentially do this same thing using new(), but I'm betting there's a more idiomatic way that's less annoying.

Thanks!

--
Matt Thiffault

Rob 'Commander' Pike

unread,
Jun 11, 2011, 5:48:13 PM6/11/11
to Matt Thiffault, golan...@googlegroups.com
Use a slice, not an array.

-rob

jimmy frasche

unread,
Jun 11, 2011, 5:49:33 PM6/11/11
to Matt Thiffault, golan...@googlegroups.com
package my

type Struct struct {
a []int
}

func New(sz int) *Struct {
return &Struct{a: make([]int, 0)}

jimmy frasche

unread,
Jun 11, 2011, 5:50:08 PM6/11/11
to Matt Thiffault, golan...@googlegroups.com
s/0/sz/

mthiffau

unread,
Jun 11, 2011, 5:51:20 PM6/11/11
to golang-nuts
I thought a slice was just pointing to an underlying array. If I
declare the struct member as a slice, is there a way I can assign it
values later on that will implicitly create the underlying array with
the proper size?

Matt Thiffault

Scott Lawrence

unread,
Jun 11, 2011, 5:52:04 PM6/11/11
to golan...@googlegroups.com
You may also wish to note the append() builtin:
http://golang.org/doc/go_spec.html#Appending_and_copying_slices

--
Scott Lawrence

signature.asc

Scott Lawrence

unread,
Jun 11, 2011, 5:52:45 PM6/11/11
to golan...@googlegroups.com

Yes, make() does that.

--
Scott Lawrence

signature.asc

mthiffau

unread,
Jun 11, 2011, 6:15:36 PM6/11/11
to golang-nuts
Here is the code I am writing:

package nn

type Neuron struct {

...

Weights []float64

...

}

func (neur Neuron) Init(weights []float64){

...

size := len(weights); // This is non-zero when I call this function,
passing in a slice of an array I've defined outside
neur.Weights = make([]float64,size)

// Copy the values in the passed array to the new one
for i,v := range weights {
neur.Weights[i] = v
}

...

}

After calling myInstance.Init([...]float64{1,2,3,4}[:]) , trying to
access any myInstance.Weights[i] causes an out-of-bounds error.

Matt Thiffault

Steven

unread,
Jun 11, 2011, 6:46:57 PM6/11/11
to mthiffau, golang-nuts

Use a pointer receiver:
func (neur *Neuron) Init(weights []float64) *Neuron { ...; return neur }

The receiver is just like any parameter (except for a couple special
case rules). What you see inside the function is a copy of what  the
caller had. By making the receiver a pointer, you get a copy of a
*pointer* to Neuron, which means you can alter the caller's Neuron
object. Otherwise, the caller's Neuron is unaltered, so their
myInstance.Weights is still nil.

The common Go idiom is to have the Init method return the receiver, so
that people can do `neur := new(Neuron).Init(...)`. This gives you
more flexibility in how you can initialize the value.

Alshere's a built-in copy function, copy(dst, src), so you don't need
the loop. Plus, you can declare use a slice literal []float64{ 5.1,
42.0, 3e3 } rather than slicing an array literal.

I would highly recommend reading the spec:
http://golang.org/doc/go_spec.html It isn't long, and from it you can
learn everything in the language (it's not much to remember, Go is a
fairly simple yet powerful language).

jimmy frasche

unread,
Jun 11, 2011, 6:54:07 PM6/11/11
to Steven, mthiffau, golang-nuts
> The common Go idiom is to have the Init method return the receiver, so
> that people can do `neur := new(Neuron).Init(...)`. This gives you
> more flexibility in how you can initialize the value.

It's even more idiomatic to have a function called New that returns the object.

Kyle Lemons

unread,
Jun 12, 2011, 3:25:12 PM6/12/11
to mthiffau, golang-nuts

After calling myInstance.Init([...]float64{1,2,3,4}[:])
You could more simply write that as []float64{1,2,3,4}.  No need to explicitly make the array and then slice it.

Ziad Hatahet

unread,
Jun 13, 2011, 3:50:51 AM6/13/11
to mthiffau, golang-nuts
       // Copy the values in the passed array to the new one
       for i,v := range weights {
               neur.Weights[i] = v
       }


Side comment -- using the built-in copy() function is probably faster than manually iterating over the elements:


--
Ziad
Reply all
Reply to author
Forward
0 new messages