Exported identifiers
An identifier may be exported to permit access to it from another package. An identifier is exported if both:
- the first character of the identifier’s name is a Unicode uppercase letter (Unicode character category Lu); and
- the identifier is declared in the package block or it is a field name or method name.
All other identifiers are not exported.
The main surprising thing to take out of this section is that an exported field or method may be accessible outside of the package even if the type it’s defined on is not!
Let’s consider an example to illustrate:
package foo
type unexported struct {
ExportedField string
unexportedField string
}
func ReturnUnexported() unexported {
return unexported{
ExportedField: "this is not secret",
unexportedField: "this is secret",
}
}
In this example, any package may import this foo
package and call ReturnUnexported()
which will return a struct of type unexported
. No other package can directly instantiate or otherwise reference this type, though, because it is unexported.
However, note that of the two fields in this struct, one is exported, and one is unexported.
If we exercise this code from our main
package, for example, we can see how it works:
package main
import "example.com/path/to/foo"
func main() {
x := foo.ReturnUnexported()
fmt.Println(x.ExportedField)
fmt.Println(x.unexportedField) // This line won't compile
}
We’ll get the following compilation error when attempting to access the unexported field:
x.unexportedField undefined (type foo.unexported has no field or method unexportedField)
Quotes from The Go Programming Language Specification Version of December 15, 2022