32

I know there is struct in Go, but for all I know, you have to define struct

type Circle struct{
    x,y,r float64
}

I am wondering how you can declare a new variable that doesn't exist in the struct

circle := new(Circle)
circle.color = "black"

4 Answers 4

64

You will need to use a map (of type map[string]interface{}) to work with dynamic JSON. Here is an example of creating a new map:

// Initial declaration
m := map[string]interface{}{
    "key": "value",
}

// Dynamically add a sub-map
m["sub"] = map[string]interface{}{
    "deepKey": "deepValue",
}

Unmarshalling JSON into a map looks like:

var f interface{}
err := json.Unmarshal(b, &f)

The code above would leave you with a map in f, with a structure resembling:

f = map[string]interface{}{
    "Name": "Wednesday",
    "Age":  6,
    "Parents": []interface{}{
        "Gomez",
        "Morticia",
    },
}

You will need to use a type assertion to access it, otherwise Go won't know it's a map:

m := f.(map[string]interface{})

You will also need to use assertions or type switches on each item you pull out of the map. Dealing with unstructured JSON is a hassle.

More information:

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

1 Comment

This answer seems to be all about JSON. I don't see in the original question where JSON is mentioned at all. Can you adjust the answer or edit the question?
18

I've started to work on this small repository https://github.com/Ompluscator/dynamic-struct

It's possible at this point to extend existing struct in runtime, by passing a instance of struct and modifying fields (adding, removing, changing types and tags).

Still in progress, so don't expect something huge :)

EDIT: At this point, work on library is done, and it looks stable for last a couple of months :)

3 Comments

You're a genius! This library is more than useful. One thing is missing, though. Unexported fields can only be added if they have a PkgPath. My suggestion: If extending a field, use the one from the model (reflect.TypeOf(model).Elem().PkgPath()) and for new structs, ask for a PkgPath or maybe try finding it out through the stack. If you want, here is what I did on quick: github.com/xdevs23/dynamic-struct/blob/master/builder.go
Thx! I'll try to add that :)
Great idea! Makes me want to make my own library 🤔
11

You can do it using reflect package, check StructOf method it allows you to create a new struct from []reflect.StructField. Example:

func main() {
typ := reflect.StructOf([]reflect.StructField{
    {
        Name: "Height",
        Type: reflect.TypeOf(float64(0)),
        Tag:  `json:"height"`,
    },
    {
        Name: "Age",
        Type: reflect.TypeOf(int(0)),
        Tag:  `json:"age"`,
    },
})

v := reflect.New(typ).Elem()
v.Field(0).SetFloat(0.4)
v.Field(1).SetInt(2)
s := v.Addr().Interface()

w := new(bytes.Buffer)
if err := json.NewEncoder(w).Encode(s); err != nil {
    panic(err)
}

fmt.Printf("value: %+v\n", s)
fmt.Printf("json:  %s", w.Bytes())

r := bytes.NewReader([]byte(`{"height":1.5,"age":10}`))
if err := json.NewDecoder(r).Decode(s); err != nil {
    panic(err)
}
fmt.Printf("value: %+v\n", s)

}

Comments

2

You can't. Go is statically typed, and does not allow such constructs.

Structs have a layout in memory that directly related to the definition, and there's no where to store such additional fields.

You can use a map instead. Moreover, you can use &circle as a key or part of a key, to associate map elements with arbitrary structs.

type key struct {
    target interface{}
    field string
}

x := make(map[key]string)
x[key{ target: circle, field: "color" }] = "black"

2 Comments

Maybe I need to re-phrase my question. Let's say I want to construct a json body. I don't know what the internal structure of the json is. How can I create a map like that?
Go through tour.golang.org, which tells you about maps and a lot of other things you will need. Then, as others say, map[string]interface{} is the type for a JSON object with unknown keys and value types (and []interface{} is a JSON array with unknown element types).

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.