David - Musings of an SRE

How to access unexported embedded structs within composite literals in Golang

Short Answer, you can’t. BUT you can still declare it.

If you have two struct types which is embedded within one another but declared as an unexported type, you will not be able to declare it in a composite type. You can only declare it outside of an composite literal

Came across this while attempting to make use of Kubernetes’ API to declare an Deployment object.

type Deployment struct {
  metav1.TypeMeta
  Spec  DeploymentSpec

}

// in the metav1 pacakge
type TypeMeta {
  Kind  string
}

With the above structure, when we try to declare Kind from TypeMeta within Deployment, we will get an error indicating an unknown field of TypeMeta.

test := Deployment{metav1.TypeMeta: {Kind: "Test"}, Spec: Spec{}}

This is because metav1.TypeMeta is declared as a unexported type within Deployment with its lowercase reference.

In order to declare a Kind, you have to declare it from outside.

test := Deployment{Spec: Spec{}}
test.Kind = "Hello"

This is because exported fields (Kind) keep their exported status when that type is embedded.


2021 Update

It seems when I wrote this in 2017 I might have been mistaken about what constitutes an unexported field. metav1.TypeMeta here does not seem to be unexported. I’m not sure what is the original error I might have seen back then. In hindsight, I should have been more verbose and documented the actual error here so that when revisiting this issue there would be better context.


References