Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Embedding structs in golang gives error "unknown field"

i have a struct in user package called account

type Account struct {
    Tp          string `json:"type"bson:"type"`
    AccountId   string  `json:"account_id"bson:"account_id"`
    Credentials map[string]interface{} `json:"credentials,omitempty"bson:"credentials,omitempty"`
    ProfilePicture string `json:"profile_picture,omitempty"`
    Username string `json:"username"bson:"username"`
    AccessToken map[string]interface{}`bson:"access_token,omitempty"`
}

and in user/accounts im trying to embed this account struct into another struct

type returnAccount struct {
    user.Account
    AccessToken string `json:"access_token,omitempty"`
}

user package is properly imported before trying to embed i was using it successfully

finaly in a loop i am getting user accounts and making a map of returnAccount and returning from my function here is my function

func getAccounts(usr *user.AuthenticatedUser, id ...string) (accounts map[string]returnAccount) {
    accounts = make(map[string]returnAccount)
    if len(id) > 0 {
        for _, v := range id {
            for _, acnt := range usr.Accounts {
                if acnt.AccountId == v {
                    accounts[acnt.AccountId] = returnAccount{
                        Tp:       acnt.Tp,
                        AccountId:acnt.AccountId,
                    }
                }
            }
        }
        return
    }
    for _, v := range usr.Accounts {
        accounts[v.AccountId] = returnAccount{
            Tp:       v.Tp,
            AccountId:v.AccountId,
            Username: v.Username,

        }

    }
    return
}

However this code wont compile here is the error message

# sgin/api/user/accounts
api/user/accounts/getaccounts.go:16: unknown returnAccount field 'Tp' in struct literal
api/user/accounts/getaccounts.go:17: unknown returnAccount field 'AccountId' in struct literal
api/user/accounts/getaccounts.go:26: unknown returnAccount field 'Tp' in struct literal
api/user/accounts/getaccounts.go:27: unknown returnAccount field 'AccountId' in struct literal
api/user/accounts/getaccounts.go:28: unknown returnAccount field 'Username' in struct literal

everything seems pretty straightforward and simple i cannot figure out why i get this error all members i need to reach of the Account struct are exported

The reason why i need this field is i want to send access token to clients through api but not the secret and also i want to reduce the indention level

like image 562
nikoss Avatar asked Jan 16 '17 23:01

nikoss


People also ask

What is a struct in Golang?

A structure or struct in Golang is a user-defined type, which allows us to create a group of elements of different types into a single unit. Any real-world entity which has some set of properties or fields can be represented as a struct. In Go language, you are allowed to create an anonymous structure.

What are anonymous fields in Golang?

Anonymous fields are those fields which do not contain any name you just simply mention the type of the fields and Go will automatically use the type as the name of the field. You can create anonymous fields of the structure using the following syntax:

Is there any way to run this example in Golang?

You can try run this example yourself in the Go playground https://play.golang.org/p/uj0JWQSOwqY This is also being reported in a Go issue and there is an open proposal to make such initialisations more explicit https://github.com/golang/go/issues/9859

What is embedding in Go programming?

Embedding is an important Go feature making composition more convenient and useful. While Go strives to be simple, embedding is one place where the essential complexity of the problem leaks somewhat.


2 Answers

You can't initialize the fields in the embedded type directly, but you can do it like this:

accounts[v.AccountId] = returnAccount{
    Account: Account{
        Tp:        v.Tp,
        AccountId: v.AccountId,
        Username:  v.Username,
    },
}

Or, if v is of type Account, you can just use

accounts[v.AccountId] = returnAccount{
    Account: v,
}
like image 79
Andy Schweig Avatar answered Sep 27 '22 16:09

Andy Schweig


You are trying to initialize promoted fields which is not possible by composite literals. From Go spec:

A field or method f of an anonymous field in a struct x is called promoted if x.f is a legal selector that denotes that field or method f.

Promoted fields act like ordinary fields of a struct except that they cannot be used as field names in composite literals of the struct.

But you can access them using dot notation:

ra:= returnAccount{}
ra.Tp = acnt.Tp
like image 43
hassansin Avatar answered Sep 27 '22 18:09

hassansin