So I am trying to write some code that allows me to edit values in an array in a struct. This example uses "Status" as a possible value to alter, but this is just a simplification to try to get my intent across.
package main
import(
"fmt"
)
type Parent struct {
Children []Child
}
type Child struct {
Status string
}
func (p *Parent) Add() *Child {
var child Child
child.Status = "1"
p.Children = append(p.Children, child)
return &p.Children[len(p.Children)-1]
}
func main() {
var p Parent
child := p.Add()
child.Status = "2"
fmt.Println(p)
fmt.Println(child)
}
This doesn't feel "proper". How should I do this in golang? Certainly I could pass the value in as a parameter, but in my particular case I would like to edit function pointers that are inside the Child struct (not in this code to keep it short) after having added the child. That feels nicer, but maybe I just need to pass them as parameters to the Add method?
eg
func (p *Parent) Add(fn1 func(), fn2 func()) *Child {
Anyway just wondering if anybody has any thoughts on this type of situation.
I think you should create the Child
outside of the Add method and pass it in. If you want to manipulate the Child, do that before you passed it in. You might use methods on the Child
struct to do that:
func (c *Child) Init(fn1 func(), fn2 func()) {
c.Status = "1"
...
}
func (p *Parent) Add(c *Child) *Child {
p.Children = append(p.Children, c)
return c
}
func main() {
var p Parent
var child Child
child.Init(...) // <- pass something in there...
p.Add(&child)
child.Status = "2"
fmt.Println(p)
fmt.Println(child)
}
I'd suggest doing this in the simplest way possible. Remember the KISS principle. One part of the system does one and only one thing.
Following this logic, your Add(c *Child)
method should only add a child. Creating a Child
should be done separately, same for giving a Child
some unique properties.
For your OpenGL menu system, this approach fits nicely as well:
m := NewMenu()
t := NewText(text)
t.OnClick = someCallback
// Some other t initialisation.
m.Add(t)
// Some time later you can still change t if it's a pointer and m.Add
// doesn't copy.
t.OnHover = someOtherCallback
The decision on whether to keep your labels exported, or hide them and provide getters/setters is up to you, and depends solely on your system's design and consistency requirements.
Ok the following works for me. The code is changed again to try to focus more clearly on the particular issue I was having. It all comes down to properly using pointers. Thanks for the suggestions.
package main
import (
"fmt"
)
type HairColor func() string
type Parent struct {
Children []*Child
}
type Child struct {
Age int
ShowHairColor HairColor
}
func (p *Parent) Add(c *Child) {
p.Children = append(p.Children, c)
}
func main() {
var parent Parent
var child Child
child.Age = 10
parent.Add(&child)
child.ShowHairColor = func() string {
return "red"
}
fmt.Printf("%v
", parent.Children[0])
fmt.Printf("%v
", child)
fmt.Println(parent.Children[0].ShowHairColor())
}