2

I am new to Go (golang). That is why my question may be irrelevant (or impossible to answer).

I have created two structs. Both of these embed another struct. Now I want to update a field of the embedded struct inside a function.

package main

import (
    "fmt"
    "reflect"
    "time"
)

type Model struct {
    UpdatedAt time.Time
}

type Fruit struct {
    Model
    label string
}

type Animal struct {
    Model
    label string
}

func update(v interface{}) {
    reflectType := reflect.TypeOf(v)
    reflectKind := reflectType.Kind()
    if reflectKind == reflect.Ptr {
        reflectType = reflectType.Elem()
    }
    m := reflect.Zero(reflectType)
    fmt.Println(m)
}

func main() {
    apple := &Fruit{
        label: "Apple",
    }
    tiger := &Animal{
        label: "Tiger",
    }
    update(apple)
    update(tiger)
    fmt.Println(apple)
    fmt.Println(tiger)
}

I wish to implement the update function so that it will put the current time in UpdatedAt of the passed struct. I am not able to do this.

In this case, the field of Fruit and Animal is same: label, but it will not always be. Please keep that in mind when providing your suggestions.

Any guidance would be much appreciated.

2 Answers 2

5

I'd avoid reflect or interface{} if you're starting to learn go. Beginners usually fall back on them like a void * crutch. Try to use concrete types or well defined interfaces.

This should get you going:

type Timestamper interface {
    Update()
    UpdatedTime() time.Time
}

type Model struct {
    updated time.Time
}

func (m *Model) Update()                { m.updated = time.Now() }
func (m *Model) UpdatedTime() time.Time { return m.updated }

type Fruit struct {
    Model
    label string
}

type Animal struct {
    Model
    label string
}

// update will work with a `Model` `Animal` or `Fruit`
// as they all implement the `Timestamper` interface`
func update(v Timestamper) {
    v.Update()
}

Playground: https://play.golang.org/p/27yDVLr-zqd

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

Comments

4

Assuming you want to achieve this via reflection: first of all, you have to pass a pointer to the struct. You're now passing a copy of the struct, so any modifications done in update will be done on the copy, not on the instance you passed in. Then, you can lookup the field UpdatedAt in the interface passed in, and set it.

That said, that's probably not the best way to do this. Another way of doing this without reflection is:

func update(in *Model) {
   in.UpdatedAt = time.Now()
}

func main() {
   apple := &Fruit{}
   update(&apple.Model)
}

Or:

func (in *Model) update() {
   in.UpdatedAt = time.Now()
}

func main() {
   apple := &Fruit{}
   apple.update()
}

2 Comments

Thanks for your suggestion. It seems to fulfil my requirement. I will give it a try asap. I wonder if there is any way to pass the whole struct (or pointer of the struct) instead of passing only the Model (if I embed another struct and wish to update a field of that in the same function). Can you give any example on how to do it if I want to use reflection on the embedding struct (Fruit or Animal)? Thanks a lot.
You can't pass a struct to a function and expect the function to find an embedded struct in it. So, you can't do it without reflection. That said, it is usually not necessary. If you ever need to do this, you probably are trying to emulate something you did in another language.

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.