GeezerVisonThe World Wide Web, restored to 800 pixels of glory. |
| Home|About|Gaming cabinet|Archives|How it works|Starter sites |
GeezerVison is showing go101.org — Structs in Go -Go 101 Go Practices 101 Theme: dark/light
The Go Optimizations 101 and
Go Details & Tips 101 books
have been updated to Go 1.25.
If you would like to learn some Go details and facts every serveral days, please follow @zigo_101. Structs in Go
Same as C, Go also supports struct types. This article will introduce the basic knowledge of struct types and values in Go.
Struct Types and Struct Type Literals
Each unnamed struct type literal starts with a
struct keyword which is followed by a sequence of field definitions enclosed in a {}. Generally, each field definition is composed of a name and a type. The number of fields of a struct type can be zero.
The following is an unnamed struct type literal:
The above struct type has three fields. The types of the two fields
title and author are both string. The type of the pages field is int.
Some articles also call fields as member variables.
Consecutive fields with the same type can be declared together.
The size of a struct type is the sum of the sizes of all its field types plus the number of some padding bytes. The padding bytes are used to align the memory addresses of some fields. We can learn padding and memory address alignments in a later article.
The size of a zero-field struct type is zero.
A tag may be bound to a struct field when the field is declared. Field tags are optional, the default value of each field tag is a blank string. The syntax allows either string literal forms for field tags. However, in practice, struct filed tags should present as key-value pairs, and each tag should present as raw string literals (...), whereas each value in a tag should present as interpreted string literals (
"..."). For example:
Note, the tags of the
X and Y fields in the above example are identical (though using field tags as this way is a bad practice).
We can use the reflection way to inspect field tag information.
The purpose of each field tag is application dependent. In the above example, the field tags can help the functions in the
encoding/json standard package to determine the field names in JSON texts, in the process of encoding struct values into JSON texts or decoding JSON texts into struct values. The functions in the encoding/json standard package will only encode and decode the exported struct fields, which is why the first letters of the field names in the above example are all upper cased.
It is not a good idea to use field tags as comments.
Unlike C language, Go structs don't support unions.
All above shown struct types are unnamed. In practice, named struct types are more popular.
Only exported fields of struct types shown up in a package can be used in other packages by importing the package. We can view non-exported struct fields as private/protected member variables.
The field tags and the order of the field declarations in a struct type matter for the identity of the struct type. Two unnamed struct types are identical only if they have the same sequence of field declarations. Two field declarations are identical only if their respective names, their respective types and their respective tags are all identical, and they are both embedded fields or not. Please note, two non-exported struct field names from different packages are always viewed as two different names.
A struct type can't have a field of the struct type itself, neither directly nor recursively.
Struct Value Literals and Struct Value Manipulations
In Go, the form
T{...}, where T must be a type literal or a type name, is called a composite literal and is used as the value literals of some kinds of types, including struct types and the container types introduced later.
Note, a type literal
T{...} is a typed value, its type is T.
Given a struct type
S whose underlying type is struct{x int; y bool}, the zero value of S can be represented by the following two variants of struct composite literal forms:
If
S is a struct type imported from another package, it is recommended to use the second form, to maintain compatibility. Consider the case where the maintainer of the package adds a new field for type S, this will make the use of first form invalid.
Surely, we can also use the struct composite literals to represent non-zero struct value.
For a value
v of type S, we can use v.x and v.y, which are called selectors (or selector expressions), to represent the field values of v. v is called the receiver of the selectors.
Later, we call the dot
. in a selector as the property selection operator.
An example:
The last
, in a composite literal is optional if the last item in the literal and the closing } are at the same line. Otherwise, the last , is required. For more details, please read line break rules in Go.
About Struct Value Assignments
When a struct value is assigned to another struct value, the effect is the same as assigning each field one by one.
Two struct values can be assigned to each other only if their types are identical or the types of the two struct values have an identical underlying type (considering field tags) and at least one of the two types is an unnamed type.
Struct Field Addressability
The fields of an addressable struct are also addressable. The fields of an unaddressable struct are also unaddressable. The fields of unaddressable structs can't be modified. All composite literals, including struct composite literals are unaddressable.
Example:
Note that the precedence of the property selection operator
. in a selector is higher than the address-taking operator &.
Composite Literals Are Unaddressable But Can Take Addresses
Generally, only addressable values can take addresses. But there is a syntactic sugar in Go, which allows us to take addresses on composite literals. A syntactic sugar is an exception in syntax to make programming convenient.
For example,
In Field Selectors, Dereferences of Receivers Can Be Implicit
In the following example, for simplicity,
(*bookN).pages could be written as bookN.pages. In other words, bookN is dereferenced in the simplified selectors.
About Struct Value Comparisons
A struct type is comparable only if none of the types of its fields (including the fields with names as the blank identifier
_) are incomparable.
Two struct values are comparable only if they can be assigned to each other and their types are both comparable. In other words, two struct values can be compared with each other only if the (comparable) types of the two struct values are identical or their underlying types are identical (considering field tags) and at least one of the two types is unnamed.
When comparing two struct values of the same type, each pair of their corresponding fields will be compared (in the order shown in source code). The two struct values are equal only if all of their corresponding fields are equal. The comparison stops in advance when a pair of fields is found unequal or a panic occurs. In comparisons, fields with names as the blank identifier
_ will be ignored.
About Struct Value Conversions
Values of two struct types
S1 and S2 can be converted to each other's types, if S1 and S2 share the identical underlying type (by ignoring field tags). In particular if either S1 or S2 is an unnamed type and their underlying types are identical (considering field tags), then the conversions between the values of them can be implicit.
Given struct types
S0, S1, S2, S3 and S4 in the following code snippet,
In particular,
But,
In fact, two struct values can be assigned (or compared) to each other only if one of them can be implicitly converted to the type of the other.
Anonymous Struct Types Can Be Used in Field Declarations
Anonymous struct types are allowed to be used as the types of the fields of another struct type. Anonymous struct type literals are also allowed to be used in composite literals.
An example:
Generally, for better readability, it is not recommended to use anonymous struct type literals in composite literals.
More About Struct Types
There are some advanced topics which are related to struct types. They will be explained in type embedding and memory layouts later.
The digital versions of this book are available at the following places:
The Go 101 project is hosted on GitHub. Welcome to improve Go 101 articles by submitting corrections for all kinds of mistakes, such as typos, grammar errors, wording inaccuracies, description flaws, code bugs and broken links.
Tapir, the author of Go 101, has been on writing the Go 101 series books since 2016 July.
New contents will be continually added to the books (and the go101.org website) from time to time.
Tapir is also an indie game developer.
You can also support Go 101 by playing Tapir's games:
Individual donations via PayPal are also welcome.
Articles in this book:
|
| You are visitor 01402503 — GeezerVison does not store the pages you look up. Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required. |