Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to literally initialize multi-level nested structs in GO?

I am trying to literally initialize the following struct in GO:

This is the struct:

type tokenRequest struct {
    auth struct {
        identity struct {
            methods  []string
            password struct {
                user struct {
                    name   string
                    domain struct {
                        id string
                    }
                    password string
                }
            }
        }
    }
}

And this is my code:

req := &tokenRequest{
    auth: struct {
        identity: struct {
            methods: []string{"password"},
            password: {
                user: {
                    name: os.Username,
                    domain: {
                        id: "default",
                    },
                    password: os.Password,
                },
            },
        },
    },
}

https://play.golang.org/p/e8Yuk-37_nN

Can I initialize without defining all the nested structs separately (i.e. auth, identity, password, user)

Thank you.

like image 661
geexee Avatar asked Jan 10 '19 09:01

geexee


2 Answers

If you have anonymous, unnamed struct types, you can only initialize them with composite literals if you repeat the struct definition. This is very inconvenient.

So instead use named struct types, so you can use them in composite literals like this:

Types:

type domain struct {
    id string
}

type user struct {
    name     string
    domain   domain
    password string
}

type password struct {
    user user
}

type identity struct {
    methods  []string
    password password
}

type auth struct {
    identity identity
}

type tokenRequest struct {
    auth auth
}

Then initializing it (try it on the Go Playground):

req := &tokenRequest{
    auth: auth{
        identity: identity{
            methods: []string{"password"},
            password: password{
                user: user{
                    name: os.Username,
                    domain: domain{
                        id: "default",
                    },
                    password: os.Password,
                },
            },
        },
    },
}

See related question: Unexpected return of anonymous struct

like image 135
icza Avatar answered Nov 15 '22 05:11

icza


You can, but you're going to be typing a lot:

package main

import (
    "fmt"
    "net/http"
)

type tokenRequest struct {
    auth struct {
        identity struct {
            methods  []string
            password struct {
                user struct {
                    name   string
                    domain struct {
                        id string
                    }
                    password string
                }
            }
        }
    }
}

func main() {
    s := tokenRequest{
        auth: struct {
            identity struct {
                methods  []string
                password struct {
                    user struct {
                        name   string
                        domain struct {
                            id string
                        }
                        password string
                    }
                }
            }
        }{
            identity: struct {
                methods  []string
                password struct {
                    user struct {
                        name   string
                        domain struct {
                            id string
                        }
                        password string
                    }
                }
            }{
                methods: []string{http.MethodGet, http.MethodPost},
                password: struct {
                    user struct {
                        name   string
                        domain struct {
                            id string
                        }
                        password string
                    }
                }{
                    user: struct {
                        name   string
                        domain struct {
                            id string
                        }
                        password string
                    }{
                        name: "username",
                        domain: struct {
                            id string
                        }{
                            id: "domain id",
                        },
                        password: "password",
                    },
                },
            },
        },
    }

    fmt.Printf("%+v\n", s)
}

You have to tell Go what type of variable you're initializing, so you just define the same anonymous struct, slowly but surely removing a level each time.

For this reason, it's better to use named structs so you don't have to repeat yourself.

like image 39
syntaqx Avatar answered Nov 15 '22 04:11

syntaqx