0

I have a data structure like this:

type (
  parent struct {
    Items []*child
  }
  child struct {
    Field string `json:"field"`
  }
)

I also want parent to have methods:

func (p *parent) example() { }

However the json requirement is that parent is just an array:

[
  {
    "field": "data"
  }
]

I want parent to be a simple array, but in order for parent to have methods, it cannot be an array type.

Is there a way to solve both problems with one data structure?

(To make matters more complicated, the actual data structure I have to work with has two levels of this: greatgrandparent contains []grandparent, and grandparent has a parent that contains []child. The json structure is externally defined, the arrays have no key names, and I would like methods on each of the four structs.)

0

1 Answer 1

1

in order for parent to have methods, it cannot be an array type.

It can, it just MUST have a name because only named types (or pointers to named types) can implement methods. The following is valid Go code:

type parent []*child

func (p parent) example() { /* ... */ }

Note that the above parent is a slice and not an array. Arrays in Go have static length, you cannot grow them and you cannot shrink them, slices on the other hand have dynamic length and you can resize them at will. Arrays and slices are closely related but not the same.


An alternative would be to have the struct type implement the json.Unmarshaler/json.Marshaler interfaces:

type parent struct { Items []*child }

func (p *parent) UnmarshalJSON(data []byte) error {
    return json.Unmarshal(data, &p.Items)
}

func (p parent) MarshalJSON() ([]byte, error) {
    return json.Marshal(p.Items)
}

The above will produce the required JSON structure.

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

5 Comments

Another thing to pay attention to is the use of * (or not) in the method definition. e.g., func (s *parentStruct) example() versus func (a parentArray) example(). This ultimately was my blind spot.
@jws anytime you have a method that will be modifying the receiver, the method should be declared with a pointer receiver.
For a non-modifying receiver method, does the pointer save object copy? Or have I been unnecessarily using *myStruct almost always for structs?
@jws whenever the method is invoked a copy of the receiver is created. If the receiver is a pointer then the pointer is copied, which is about 8 bytes, the pointed-to-object is not copied. If the receiver is not a pointer then the object itself is copied, this becomes a copy of about unsafe.Sizeof(object) bytes. Copying is fast and even big objects may be easier to memory_manage than pointers, however the object could become so large that a pointer becomes more than warranted.
Solved cleanly as suggested: a type to name the array, and use of indirection in the methods - func (p *parent) example() and inside, things like len(*p), instead of len(p.Items). Thanks!

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.