0

Here is my data structure and trying to create a struct for this data but failing within error.

{
                "data": {
                  "image": {
                    "url": "tests.jpg"
                  }
                }
              }

Error:-

prog.go:16:20: invalid field name "Data" in struct initializer
prog.go:16:22: missing type in composite literal

Code:-

package main

import (
    "fmt"
)

type Images struct {
    Data struct {
        Image struct {
            url string
        }
    }
}

func main() {
    i := Images{"Data": {"Image": {"url": "test.jpg"}}}
    fmt.Println(i)
}

After reading the below answer, I tried this -

package main

import (
    "fmt"
)

//{ "data": {
//                  "image": {
//                    "url": "tests.jpg"
//                  }
//                }
//              }

type Images struct {
    Data Data
}
type Data struct {
    Image Image
}

type Image struct {
    url string
}

func main() {
    i := Images{
        Data: Data{
            Image: Image{url: "test.jpg"}}}
    fmt.Println(i)
}

Final output:-

{{{test.jpg}}}
user1050619
  • 19,822
  • 85
  • 237
  • 413
  • https://stackoverflow.com/questions/24809235/initialize-a-nested-struct-in-golang – oakad Aug 15 '18 at 02:02
  • 4
    Possible duplicate of [Initialize a nested struct in Golang](https://stackoverflow.com/questions/24809235/initialize-a-nested-struct-in-golang) – daplho Aug 15 '18 at 02:10

1 Answers1

1

There are a number of easy to conflate issues going on here.

Output:

First and foremost is you're not specifying any particular output formatting. Using fmt.Println to output data structures is really just for easy debugging, the formatting is pretty arbitrary you could get more reliably formatted output in correct Go if you used fmt.Printf("%#v\n", i). The default Println outputs the equvelent of Printf's "%v".

To get output in a particular format (other then Go itself) you'll need to import a package that can generate that format. Luckily a few popular formats are included in the standard library. But before we can get to that there are a few other things to fix / understand.

Exports:

Capitalized members of a struct are exported lower case members are not. This means that "url"in your image structure MUST be capitalized or else packages such as encoding/json will be unable to access the member to export it.

Anonymous Types:

Others emphasize creating explicit definitions for each of the structured data types in the overall structure, and I think that is generally good advice. However, it is also often silly to have so many one off type definitions floating around, so it is completely acceptable in the language to use inline anonymous structure definitions. Also a nice touch is that identically structured anonymous types are accepted as the same type unlike defined types.

Here's an, admittedly pathological, example of doing the above with anonymous structs.

i := struct{
    Data interface{} `json:"data"`
}{
    Data:struct{
        Image interface{} `json:"image"`
    } {
        Image:struct{
            Url string `json:"url"`
        }{
            Url:"test.jpg",
        },
    },
}

While this works it's pretty messy. But notice you can even add tags to the fields of anonymous types so json formatting translates as intended.

Another way to do it anonymously and avoid all this type definition crazy is just use a map. Here's that example. Note however, that some Go cargo cultists will yell at you if they see you using map[string]interface{} everywhere. Nevertheless there's actually nothing wrong with it either in practice or in philosophy.

j := map[string]interface{} {
    "data":map[string]interface{}{
        "image":map[string]interface{}{
            "url":"test.jpg",
        },
    },
}

Generally however, you want to take advantage of what a typed language can give you. Strongly typed languages like Go are very good at finding otherwise subtile bugs early on.

And isn't this better looking:

type Object map[string]interface{}

// ...

j := Object{
    "data": Object{
        "image": Object{
            "url":"test.jpg",
        },
    },
}

Once More With Encoding

Here's your program in a more idiomatic style. Which, not coincidentally, is also more readable in my opinion.

    package main

    import (
        "fmt"
        "encoding/json"
    )

    type data struct {
        Image image `json:"image"`
    }

    type image struct {
        Url string `json:"url"`
    }

    type images struct {
        Data data `json:"data"`
    }


    func main() {
        i := images{Data: data{Image: image{Url: "test.jpg"}}}

        data, _ := json.Marshal(i)
        fmt.Println(string(data))

    }

Also note that while you must export the members to have them appear in the json, you do not have to export the types themselves.

Joshua Kolden
  • 416
  • 6
  • 16