2

I have a function that looks like this:

func Foo(result interface{}) error {
     ...
     json.Unmarshal([]byte(some_string), result)
     ...
}

Which is called like this:

var bar Bar
Foo(&bar)

Generally, Foo fetches a string that is then unmarshalled into the result. However, now I need to update it so that Foo sometimes loads data from another source and returns that instead.

type Loader func() (interface{})

func Foo(result interface{}, Loader load) error {
     ...
     data := load()
     // result = data ???
     ...
}

Is there any way for me to assign this new value to result? I found that I can marshal the data into a string and then unmarshal it into result which works, but I can't imagine that's the best way.

0

1 Answer 1

5

You can do,

p := result.(*Bar)
*p = data

The first line is a type assertion.

The second assigns data to the dereferenced pointer. Assigning a value to a dereferenced pointer changes the value at the referenced address.

Since you don't know the underlying types of result or data the best you can do is using a type assertion switch.

switch v := data.(type) {
case Bar:
    // If 'data' is of type 'Bar'
    p, ok := result.(*Bar)
    if(!ok){
        // This means inputs were bad.
        // 'result' and 'data' should both have the same underlying type.
        fmt.Println("underlying types mismatch")
        break;
    }

    *p = v

case Baz:
    // If 'data' is of type 'Baz'
    // Equivalent of above for 'Baz'
}

See Type Switches from switch statement

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

3 Comments

Only problem is that I don't know the concrete type of result inside of Foo. That's why I'm using interface{}. Do I need to use reflect to figure that out?
Bill, sorry I overlooked it. Updated the answer with the best solution I could come up with. I hope you have thought through using this API. Maybe you could change it to just return data instead of assigning it to a pointer?
I need to pass in a referenced struct for the deserialization case anyways and no matter how I refactor I'm always going to eventually get down to a point where I'm either loading a struct or deserializing a string. It ends up being something like foo(result interface{}, load Loader) (interface{}, error) which is fine but not as clean as I was hoping for.

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.