Go Structs: Difference between revisions

From NovaOrdis Knowledge Base
Jump to navigation Jump to search
 
(148 intermediate revisions by the same user not shown)
Line 7: Line 7:
Structs are user-defined [[Go_Language#Composite_Types|composite types]], grouping together instances of arbitrary types, into one object.
Structs are user-defined [[Go_Language#Composite_Types|composite types]], grouping together instances of arbitrary types, into one object.


A struct declaration consists in a series of fields, where each fields has an arbitrary name and a type. A struct may also contain other types, named [[#Embedded_Types|embedded types]] and also methods that operate on the structure's fields. The fields usually represent a ''has-a'' relationship, consistent with the struct's composite type nature.
A struct declaration consists in a sequence of '''named elements''', called '''fields'''. Each field has one or more names and a type. The name(s) can be explicitly listed in the structure, or can be implicit, for '''embedded fields'''. A field may optionally have a '''tag'''. More details about fields can be found in the [[#Fields|Fields]] section.  
 
A struct variable is a value, not a [[Go_Language#.28No.29_Reference_Variables|reference variable]], which means that no two different struct variables may point to the same struct instance.


Structs can represent data values that could have either a [[Go_Language#The_Primitive_vs._Non-Primitive_Nature_of_Types|primitive or non-primitive value]]. "Primitive" structs imply creating a new instance every time an existing value is mutated. In this case, values themselves, rather than pointers, are used to share values of those structs. An example is the <code>Time</code> structure in the <code>[[Go Package time|time]]</code> package. However, in most cases, structs exhibit a non-primitive structure: adding or removing something from the value mutates the value, does not create a new value.
Structs can represent data values that could have either a [[Go_Language#The_Primitive_vs._Non-Primitive_Nature_of_Types|primitive or non-primitive value]]. "Primitive" structs imply creating a new instance every time an existing value is mutated. In this case, values themselves, rather than pointers, are used to share values of those structs. An example is the <code>Time</code> structure in the <code>[[Go Package time|time]]</code> package. However, in most cases, structs exhibit a non-primitive structure: adding or removing something from the value mutates the value, does not create a new value.
=Printing Structs=
To print the abbreviated struct, and only display values, and not field names, use:
<syntaxhighlight lang='go'>
fmt.Println(s)
</syntaxhighlight>
To print both field names and values, use the  <code>%+v</code> format specifier:
<syntaxhighlight lang='go'>
fmt.Printf("%+v\n", s)
</syntaxhighlight>


=Declaration=
=Declaration=
The struct type definition is introduced by the <code>type</code> [[Go_Language#Keywords|keyword]], to indicate that this is a user-defined type, followed by the new type name and the keyword <code>struct</code>, followed by a curly-brackets-enclosed enumeration of fields. Each field is defined by an arbitrary name and a type. The type can be a [[Go_Language#Pre-Declared_Types|pre-declared type]] or a user-defined type, such as another <code>struct</code> or an [[Go_Interfaces#Interfaces_as_Fields|interface]].
Struct types can be declared at package level or inside a function.
 
The struct type definition is introduced by the <code>type</code> [[Go_Language#Keywords|keyword]], to indicate that this is a user-defined type, followed by the new type name and the keyword <code>struct</code>, followed by a curly-brackets-enclosed enumeration of fields.  
 
Once the struct type has been defined in a package or a function, variables of that type can be declared using the [[Go_Language#Variable_Declaration|long declaration]]:
<syntaxhighlight lang='go'>
var i Item
</syntaxhighlight>
If no explicit initialization follows, the struct variables declared as above have all their fields initialized with [[Go_Language#Zero_Value|zero values]. [[Go_Language#Short_Variable_Declaration|Short declaration]] can also be used, as shown in the [[#Initialization|Initialization]] section, below.
==<span id='Field'></span>Fields==
 
Each field has '''one or more names''' and a '''type'''. The type can be a [[Go_Language#Pre-Declared_Types|pre-declared type]] or a user-defined type, such as another <code>struct</code> or an [[Go_Interfaces#Interfaces_as_Fields|interface]]. No comma is required at the end of the field line. The name(s) can be explicitly listed in the structure, or can be implicit, in case of [[#Embedded_Fields|embedded fields]]. A field may optionally have a [[#Tag|tag]]. Within a struct, non-blank field names must be unique.
 
<span id='Has-A_Relationship'></span>A named field usually represents a '''has-a''' relationship, consistent with the struct's composite type nature, and an embedded field represents an '''is-a''' relationship (see [[#Embedded_Fields|below]]).


Struct types can be declared at package level or inside a function.
Fields can be [[Go_Packages#Export|exported]] outside the package declaring the type. For more details see the [[#Exporting_Fields|Exporting Fields]] section.


These are named fields:
<syntaxhighlight lang='go'>
<syntaxhighlight lang='go'>
type Item struct {
type Item struct {
Line 22: Line 49:
}
}
</syntaxhighlight>
</syntaxhighlight>
 
A field with multiple names can be declared as such:
Fields with the same types can be collapsed:
 
<syntaxhighlight lang='go'>
<syntaxhighlight lang='go'>
type SomeStruct struct {
type Item struct {
  ...
    a, b, c int
  i, j, k int
  ...
}
}
</syntaxhighlight>
</syntaxhighlight>
 
We say that fields with the same types can be collapsed. This structure is fully equivalent with the structure where each of the names is declared on its own line:
Once the type has been defined in a package or a function, variables of that type can be declared using the [[Go_Language#Variable_Declaration|long declaration]]:
<syntaxhighlight lang='go'>
<syntaxhighlight lang='go'>
var i Item
type Item struct {
    a int
    b int
    c int
}
</syntaxhighlight>
</syntaxhighlight>
If no explicit initialization follows, the struct variables declared as above have all their fields initialized with [[Go_Language#Zero_Value|zero values]].
===<span id='Embedded_Type'></span><span id='Embedded_Field'></span><span id='Embedded_Field_Promotion'></span><span id='Promoted_Fields'></span><span id='Embedded_Field_Identity'></span><span id='Overriding_Embedded_Fields'></span><span id=''></span><span id=''></span><span id=''></span><span id=''></span><span id=''></span>Embedded Fields===
 
[[Go_Language#Short_Variable_Declaration|Short declaration]] can also be used, as shown in the [[#Initialization|Initialization]] section, below.


=Literal=
Embedded fields, embedded field promotion, promoted fields, embedded field identity, overriding embedded fields are discussed in the following article: {{Internal|Go_Structs_Embedded_Fields#Overview|Embedded Fields}}
Struct literals can have all field initialization values on the same line, or on different lines:


===<span id='Blank_Field'></span>Blank Fields===
<syntaxhighlight lang='go'>
<syntaxhighlight lang='go'>
i := Item{color: "blue, size: 5}
type Item struct {
_ float32 // a blank field
    _ int // another blank field
}
</syntaxhighlight>
</syntaxhighlight>
 
===<span id='Tag'></span>Tags===
A field declaration may be followed by an optional string literal '''tag''', which is a string literal declared between <code>`...`</code> (backticks). A tag becomes an '''attribute''' for all the fields in the corresponding field declaration. The tags are made visible through a reflection interface and take part in type identity for structs but are otherwise ignored.
<syntaxhighlight lang='go'>
<syntaxhighlight lang='go'>
i := Item {
type A struct {
  color: "blue,
    Name string `json:"name"`
  size: 5, // mandatory comma
}
}
</syntaxhighlight>
</syntaxhighlight>
In the example above, a tag has been included to provide '''metadata''' the JSON decoding function needs to parse JSON content. Each tag maps a field name in the struct to a filed name in the JSON document. Tags are useful in [[JSON_in_Go#Overview|JSON]] and [[YAML_in_Go#Overview|YAML]] serialization/deserialization.


=Initialization=
=<tt>struct</tt> Zero Value=
<span id='new'></span>Initialize a struct variable with an empty struct using the <code>[[Go_Built-In_Function_new|new()]]</code> [[Go_Functions#Built-in_Functions|built-in function]] and the [[Go_Language#Short_Variable_Declaration|short variable declaration]]:
 
<font color=darkkhaki>Expand this, <code>struct</code> zero value is important when [[YAML_in_Go#Behavior_when_an_Entire_Subtree_Is_Missing|parsing YAML and entire subtrees are missing]].</font>
=Empty <tt>struct</tt>=
An empty struct allocates zero bytes when values of this type are created. They are useful when a type, but not state, is needed. Example:
<syntaxhighlight lang='go'>
<syntaxhighlight lang='go'>
i := new(Item)
// we declared an empty struct that defines the type "A"
type A struct{}
 
a := A{}
b := struct{}{}
</syntaxhighlight>
</syntaxhighlight>


This results in an "empty" structure, with all fields initialized to zero.
=<span id='Idiomatic_Struct_Naming_Conventions'></span>Naming=
Struct names should follow the general Go naming conventions:
{{Internal|Go_Style#Naming|Go Naming}}


A [[#Literal|struct literal]] can also be used:
=<span id='Literal'></span>Composite Literal=
Struct composite literals are expressions that create a new instance of the structure every time they are evaluated. The fields of a composite literal must be laid out in order and must be all present:
<syntaxhighlight lang='go'>
<syntaxhighlight lang='go'>
i := Item{color: "blue, size: 5}
i := Item{"blue", 5}
</syntaxhighlight>
</syntaxhighlight>


=Operators=
However, by labeling the elements explicitly as <code>field:value</code> pairs, the initializers can appear in any order, with the missing ones left as their respective zero values:
==The Dot Operator==
Individual fields in a struct can be read and modified using the "dot notation":
<syntaxhighlight lang='go'>
<syntaxhighlight lang='go'>
var i Item
i := Item{size: 5}
i.color = "blue"
i.size = 2
 
fmt.Printf("color %s, size %d\b", i.color, i.size)
</syntaxhighlight>
</syntaxhighlight>
=Embedded Types=


=TO DISTRIBUTE=
Composite literals can have all field initialization values on the same line, or on different lines:
<font color=darkkhaki>
The short variable declaration uses the short variable declaration operator [[Go_Concepts_-_Operators#:.3D|:=]]


====Literal====
<syntaxhighlight lang='go'>
i := Item{color: "blue", size: 5}
</syntaxhighlight>


Struct literal initialization comes in two forms.
<syntaxhighlight lang='go'>
 
i := Item {
1. All the values are specified on the same line:
  color: "blue",
 
  size: 5, // mandatory comma
<pre>
ms := myStruct{i: 5, s: "something"}
</pre>
 
or
 
2. Values are specified on separate lines:
 
<pre>
ms := myStruct{
    i: 5,  
    s: "something",
}
}
</pre>
</syntaxhighlight>


Note the trailing comma when using the multi-line literal.
There is "short" literal where the name of the fields are omitted, given that values for '''all''' fields are provided, the order in which they are declared is maintained:


There is a shorter struct literal where the name of the fields are omitted, provided that the order is maintained:
<syntaxhighlight lang='go'>
i := Item {"blue", 5}
</syntaxhighlight>


<pre>
It is possible to initialize just some of the fields, but in this case the field names must be provided. The remaining fields will be initialized to their zero value:
ms := myStruct{5, "something"}
<syntaxhighlight lang='go'>
</pre>
i := Item {color:"blue"}
</syntaxhighlight>


=====Embedded Literals=====
==Embedded Literals==
 
When a field of a struct is another struct, embedded literals can be used in initialization:
When a field of a <tt>struct</tt> is another <tt>struct</tt>, embedded literals can be used in initialization:
<syntaxhighlight lang='go'>
 
i := Item {
<pre>
  color: "blue",
a := A {
  packaging: {
    b: B {
    material: "plastic",
      d: "something",
     protectionLevel: 10,
     }
  }
    c : "something else",
  size: 5,
}
}
</pre>
</syntaxhighlight>


====<tt>new()</tt>====
=Initialization=
<span id='new'></span>Initialize a struct variable with an empty struct using the <code>[[Go_Functions#new()|new()]]</code> [[Go_Functions#Built-in_Functions|built-in function]] and the [[Go_Language#Short_Variable_Declaration|short variable declaration]]:
<syntaxhighlight lang='go'>
i := new(Item)
</syntaxhighlight>


<tt>[[Go_Built-In_Function_new|new()]]</tt> initialization:
This results in an "empty" structure, with all fields initialized to zero. Note <code>new()</code> returns a pointer to the structure and not the structure itself.


<pre>
A [[#Literal|struct composite literal]] can also be used to initialize the structure:
msPtr := new(myStruct)
<syntaxhighlight lang='go'>
</pre>
i := Item{color: "blue", size: 5}
</syntaxhighlight>


Note <tt>new()</tt> returns a ''pointer'' to the structure and not the structure itself.
==Make Zero Value Useful==


==Fields==
It is good practice to design the type to be usable with its zero values, right away, without additional initialization, if possible. This means a user of the data structure can create one with <code>new()</code> and get it right to work. For example, the documentation for <code>bytes.Buffer</code> states that "the zero value for <code>Buffer</code> is an empty buffer ready to use". Similarly, <code>sync.Mutex</code> does not have an explicit constructor or <code>Init()</code> method. Instead, the zero value for <code>sync.Mutex</code> is defined to be an unlocked mutex. The zero-value-is-useful property works transitively, if a structure is composed by two types that works while initialized with zero value, the composite structure works while initialized with zero value.


Fields can be access with the <tt>[[Go_Concepts_-_Operators#.|.]]</tt> operator.  
==Initializing Struct Fields to Something Else than Zero Value==
<font color=darkkhaki>It seems not to be possible. If I have a Set structure that internally contains a map, I have two options:


Note that the <tt>.</tt> operator works with a regular <tt>struct</tt> variable as well as with a pointer to a <tt>struct</tt>: the compiler knows how to compensate for both of these cases. Also see [[Go_Concepts_-_Operators#Field_Access|<tt>.</tt> used for field access]].
1. Use a NewSet() constructor that initializes the map.


<pre>
2. Do lazy initialization on operations.
ms := myStruct{1, "s"}
</font>
msPtr := new(myStruct)


// valid:
=Operators=
ms.i
==<span id='The_Dot_Operator'></span>The Selector Operator==
Individual fields in a struct can be read and modified using the "dot notation", the <code>[[Go_Concepts_-_Operators#.|.]]</code> [[Go_Language#Selector_Operator|selector operator]].
<syntaxhighlight lang='go'>
var i Item
i.color = "blue"
i.size = 2


// valid:
fmt.Printf("color %s, size %d\b", i.color, i.size)
msPtr.i
</syntaxhighlight>
</pre>


Even if the enclosing struct type is [[Go Concepts - Packages#Exported_Identifiers|exported]] by a package, not all fields are exported automatically, only those whose first character is an upper case letter. This behavior makes possible to have "private" fields in a public structure, when the structure is used outside its package.
<span id='Selector_Operator_Versatility'></span>Note that the <code>.</code> operator works with a regular struct variable as well as with a pointer to the struct. The compiler takes care of the underlying details to access the value and knows how to compensate for both of these cases:


===Field Tags and Attributes===
<syntaxhighlight lang='go'>
 
type SomeStruct struct {
A field declaration may be followed by an optional string literal ''tag'', which becomes an ''attribute'' for all the fields in the corresponding field declaration. The tags are made visible through a reflection interface and take part in type identity for structs but are otherwise ignored.
  i int
 
Example:
 
<pre>
type A struct {
    name string `json:"name"`
}
}
</pre>


In the example above, tags have been included to provide ''metadata'' the JSON decoding function needs to parse JSON content. Each tag maps a field name in the <tt>struct</tt> type to a filed name in the JSON document.
s := SomeStruct{10}
s2 := &s


==Embedded Types==
fmt.Printf("%d\n", s.i)  // the selector operator is applied to a value 
fmt.Printf("%d\n", s2.i)  // the selector operator is applied to a pointer
</syntaxhighlight>


An embedded type is initialized by declaring a name of a struct inside other <tt>struct</tt> - ''without associating it with a field''. An embedded type is sometimes referred to as ''anonymous field''. It models an ''is-a'' relationship. Example:
=Exporting Structs=
<font size='darkkhaki>"Exporting Structs" section needs refactoring.</font>


<pre>
Even if the enclosing struct type is [[Go_Language_Modularization#Exported_Identifiers|exported]] by a package, not all fields are exported automatically, only those whose first character is an upper case letter. This behavior makes possible to have "private" fields in a public structure, when the structure is used outside its package.
type A struct {
==Encapsulation and Private Fields==
    f1 int
<font color=darkkhaki>
}
Formally define the semantics of fields that start with lower case names. They are "hidden". What exactly does that mean? Apparently, other package cannot see them.
 
</font color>
type B struct {
Aslo see: {{Internal|Go_Language_Object_Oriented_Programming#Encapsulation|Object Oriented Programming in Go &#124; Encapsulation}}
    A
==<span id='Exported_Fields'></span>Exporting Fields==
    f2 int
The fields of an [[Go_Packages#Exporting_Package_Members|exported]] <tt>struct</tt> type can be exported or unexported on a field-by-field basis, by naming them with an uppercase and respectively lowercase letter.
}
</pre>
 
===Methods and Embedded Types===
 
A pointer receiver method associated with the embedded type also works with the embedding type. For example, if there's a:
 
<pre>
func (a *A) m1(...) {
    ...
}
</pre>
<tt>m1()</tt> also works directly with B instances as such:
 
<pre>
bPtr := new(B)
...
bPtr.m1(...)
</pre>


In the code sequence above, the invocations <tt>bPtr.m1(...)</tt> and <tt>bPtr.A.m1(...)</tt> are equivalent.
<font color=darkkhaki>What if the struct is named with a lowercase letter and the field starts with an uppercase letter?</font>


==Empty Structs==
<font color=darkkhaki>Explain this behavior: [[YAML_in_Go#TODO_Ee4]].</font>


An empty struct allocates zero bytes when values of this type are created. They are useful when a type (but not state) is needed. Example:
==<span id='Embedded_Type_Export'></span><span id='Exporting_Embedded_Types'></span>Exporting Embedded Fields==
If the name of an [[#Embedded_Field|embedded field]] starts with a lower case, it is unexported even if its outer type is [[Go_Packages#Embedded_Type_Export|exported]]. Even if the name of the inner type is not exported, its fields may be individually exported, and thus accessible from outside the package.


<pre>
=Structs as Receiver Types=
// we declared an empty struct that defines the type "A"
{{Internal|Go_Language_Object_Oriented_Programming#Structs_as_Receiver_Types|Object Oriented Programming in Go &#124; Structs as Receiver Types}}
type A struct{}
</pre>

Latest revision as of 02:10, 4 November 2024

External

Internal

Overview

Structs are user-defined composite types, grouping together instances of arbitrary types, into one object.

A struct declaration consists in a sequence of named elements, called fields. Each field has one or more names and a type. The name(s) can be explicitly listed in the structure, or can be implicit, for embedded fields. A field may optionally have a tag. More details about fields can be found in the Fields section.

A struct variable is a value, not a reference variable, which means that no two different struct variables may point to the same struct instance.

Structs can represent data values that could have either a primitive or non-primitive value. "Primitive" structs imply creating a new instance every time an existing value is mutated. In this case, values themselves, rather than pointers, are used to share values of those structs. An example is the Time structure in the time package. However, in most cases, structs exhibit a non-primitive structure: adding or removing something from the value mutates the value, does not create a new value.

Printing Structs

To print the abbreviated struct, and only display values, and not field names, use:

fmt.Println(s)

To print both field names and values, use the %+v format specifier:

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

Declaration

Struct types can be declared at package level or inside a function.

The struct type definition is introduced by the type keyword, to indicate that this is a user-defined type, followed by the new type name and the keyword struct, followed by a curly-brackets-enclosed enumeration of fields.

Once the struct type has been defined in a package or a function, variables of that type can be declared using the long declaration:

var i Item

If no explicit initialization follows, the struct variables declared as above have all their fields initialized with [[Go_Language#Zero_Value|zero values]. Short declaration can also be used, as shown in the Initialization section, below.

Fields

Each field has one or more names and a type. The type can be a pre-declared type or a user-defined type, such as another struct or an interface. No comma is required at the end of the field line. The name(s) can be explicitly listed in the structure, or can be implicit, in case of embedded fields. A field may optionally have a tag. Within a struct, non-blank field names must be unique.

A named field usually represents a has-a relationship, consistent with the struct's composite type nature, and an embedded field represents an is-a relationship (see below).

Fields can be exported outside the package declaring the type. For more details see the Exporting Fields section.

These are named fields:

type Item struct {
    color string
    size int
}

A field with multiple names can be declared as such:

type Item struct {
    a, b, c int
}

We say that fields with the same types can be collapsed. This structure is fully equivalent with the structure where each of the names is declared on its own line:

type Item struct {
    a int
    b int
    c int
}

Embedded Fields

Embedded fields, embedded field promotion, promoted fields, embedded field identity, overriding embedded fields are discussed in the following article:

Embedded Fields

Blank Fields

type Item struct {
	_ float32 // a blank field
    _ int // another blank field
}

Tags

A field declaration may be followed by an optional string literal tag, which is a string literal declared between `...` (backticks). A tag becomes an attribute for all the fields in the corresponding field declaration. The tags are made visible through a reflection interface and take part in type identity for structs but are otherwise ignored.

type A struct {
    Name string `json:"name"`
}

In the example above, a tag has been included to provide metadata the JSON decoding function needs to parse JSON content. Each tag maps a field name in the struct to a filed name in the JSON document. Tags are useful in JSON and YAML serialization/deserialization.

struct Zero Value

Expand this, struct zero value is important when parsing YAML and entire subtrees are missing.

Empty struct

An empty struct allocates zero bytes when values of this type are created. They are useful when a type, but not state, is needed. Example:

// we declared an empty struct that defines the type "A"
type A struct{}

a := A{}
b := struct{}{}

Naming

Struct names should follow the general Go naming conventions:

Go Naming

Composite Literal

Struct composite literals are expressions that create a new instance of the structure every time they are evaluated. The fields of a composite literal must be laid out in order and must be all present:

i := Item{"blue", 5}

However, by labeling the elements explicitly as field:value pairs, the initializers can appear in any order, with the missing ones left as their respective zero values:

i := Item{size: 5}

Composite literals can have all field initialization values on the same line, or on different lines:

i := Item{color: "blue", size: 5}
i := Item {
  color: "blue",
  size: 5, // mandatory comma
}

There is "short" literal where the name of the fields are omitted, given that values for all fields are provided, the order in which they are declared is maintained:

i := Item {"blue", 5}

It is possible to initialize just some of the fields, but in this case the field names must be provided. The remaining fields will be initialized to their zero value:

i := Item {color:"blue"}

Embedded Literals

When a field of a struct is another struct, embedded literals can be used in initialization:

i := Item {
  color: "blue",
  packaging: {
    material: "plastic",
    protectionLevel: 10,
  }
  size: 5,
}

Initialization

Initialize a struct variable with an empty struct using the new() built-in function and the short variable declaration:

i := new(Item)

This results in an "empty" structure, with all fields initialized to zero. Note new() returns a pointer to the structure and not the structure itself.

A struct composite literal can also be used to initialize the structure:

i := Item{color: "blue", size: 5}

Make Zero Value Useful

It is good practice to design the type to be usable with its zero values, right away, without additional initialization, if possible. This means a user of the data structure can create one with new() and get it right to work. For example, the documentation for bytes.Buffer states that "the zero value for Buffer is an empty buffer ready to use". Similarly, sync.Mutex does not have an explicit constructor or Init() method. Instead, the zero value for sync.Mutex is defined to be an unlocked mutex. The zero-value-is-useful property works transitively, if a structure is composed by two types that works while initialized with zero value, the composite structure works while initialized with zero value.

Initializing Struct Fields to Something Else than Zero Value

It seems not to be possible. If I have a Set structure that internally contains a map, I have two options:

1. Use a NewSet() constructor that initializes the map.

2. Do lazy initialization on operations.

Operators

The Selector Operator

Individual fields in a struct can be read and modified using the "dot notation", the . selector operator.

var i Item
i.color = "blue"
i.size = 2

fmt.Printf("color %s, size %d\b", i.color, i.size)

Note that the . operator works with a regular struct variable as well as with a pointer to the struct. The compiler takes care of the underlying details to access the value and knows how to compensate for both of these cases:

type SomeStruct struct {
  i int
}

s := SomeStruct{10}
s2 := &s

fmt.Printf("%d\n", s.i)   // the selector operator is applied to a value  
fmt.Printf("%d\n", s2.i)  // the selector operator is applied to a pointer

Exporting Structs

"Exporting Structs" section needs refactoring.

Even if the enclosing struct type is exported by a package, not all fields are exported automatically, only those whose first character is an upper case letter. This behavior makes possible to have "private" fields in a public structure, when the structure is used outside its package.

Encapsulation and Private Fields

Formally define the semantics of fields that start with lower case names. They are "hidden". What exactly does that mean? Apparently, other package cannot see them.

Aslo see:

Object Oriented Programming in Go | Encapsulation

Exporting Fields

The fields of an exported struct type can be exported or unexported on a field-by-field basis, by naming them with an uppercase and respectively lowercase letter.

What if the struct is named with a lowercase letter and the field starts with an uppercase letter?

Explain this behavior: YAML_in_Go#TODO_Ee4.

Exporting Embedded Fields

If the name of an embedded field starts with a lower case, it is unexported even if its outer type is exported. Even if the name of the inner type is not exported, its fields may be individually exported, and thus accessible from outside the package.

Structs as Receiver Types

Object Oriented Programming in Go | Structs as Receiver Types