This article will introduce all kinds of types in Go. All kinds of concepts in Go type system will also be introduced. Without knowing these concepts, it is hard to have a thorough understanding of Go.
string
.bool
.int8
, uint8
(byte
), int16
, uint16
, int32
(rune
), uint32
, int64
, uint64
, int
, uint
, uintptr
.float32
, float64
.complex64
, complex128
.
Note, byte
is a built-in alias of uint8
,
and rune
is a built-in alias of int32
.
We can also declare custom type aliases (see below).
Except string types, Go 101 article series will not try to explain more on other basic types.
// Assume T is an arbitrary type and Tkey is
// a type supporting comparison (== and !=).
*T // a pointer type
[5]T // an array type
[]T // a slice type
map[Tkey]T // a map type
// a struct type
struct {
name string
age int
}
// a function type
func(int) (bool, string)
// an interface type
interface {
Method0(string) int
Method1() (int, bool)
}
// some channel types
chan T
chan<- T
<-chan T
Comparable and uncomparable types will be explained below.
Each of the above mentioned basic and composite types corresponds to one kind of types.
Besides these type kinds, the unsafe pointer types introduced in the
unsafe
standard package
also belong to one kind of types in Go.
So, up to now (Go 1.12), Go has 26 kinds of types.
(Type definition, or type definition declaration, was called type declaration and was the only type declaration way before Go 1.9. Since Go 1.9, type definition has become one of two forms of type declarations in Go. The other new form is called type alias declaration, which will be introduced in the next section.)
type
is a keyword.
// Define a solo new type.
type NewTypeName SourceType
// Define multiple new types together.
type (
NewTypeName1 SourceType1
NewTypeName2 SourceType2
)
New type names must be identifiers.
The second type declaration in the above example includes two type specifications.
If a type declaration contains more than one type specifications,
the type specifications must be enclosed within a pair of ()
.
// The following new defined and source types
// are all basic types.
type (
MyInt int
Age int
Text string
)
// The following new defined and source types are
// all composite types.
type IntPtr *int
type Book struct{author, title string; pages int}
type Convert func(in0 int, in1 bool)(out0 int, out1 string)
type StringArray [5]string
type StringSlice []string
func f() {
// The names of the three defined types
// can be only used within the function.
type PersonAge map[string]int
type MessageQueue chan string
type Reader interface{Read([]byte) int}
}
(Type alias declaration is one new kind of type declarations added since Go 1.9.)
As above mentioned, there are only two built-in type aliases in Go,
byte
(alias of uint8
) and
rune
(alias of int32
).
They are the only two type aliases before Go 1.9.
=
in each type alias declaration.
type (
Name = string
Age = int
)
type table = map[string]int
type Table = map[Name]Age
Type alias names must be identifiers. Like type definitions, type aliases can also be declared within function bodies.
Name
is an alias of string
,
they denote the same type.
The same relation is for the other three pairs of type names and literals:
Age
and int
table
and map[string]int
Table
and map[Name]Age
In fact, the literals map[string]int
and map[Name]Age
also denote the same type.
So, the same, aliases table
and Table
also denote the same type.
Note, although aliases table
and Table
denote the same type,
Table
is exported so it can be used by other packages
but table
can't.
A defined type is a type defined in a type definition or an alias of another defined type.
All basic types are defined. A non-defined type must be a composite type.
C
and type literal
[]string
are both non-defined types,
but type A
and type alias B
are both defined types.
type A []string
type B = A
type C = []string
unsafe.Pointer
which is defined in the unsafe
standard code package.// The underlying types of the following ones are both int.
type (
MyInt int
Age MyInt
)
// The following new types have different underlying types.
type (
IntSlice []int // underlying type is []int
MyIntSlice []MyInt // underlying type is []MyInt
AgeSlice []Age // underlying type is []Age
)
// The underlying types of []Age, Ages, and AgeSlice
// are all the non-defined type []Age.
type Ages AgeSlice
How to trace to the underlying type for a given user declared type?
The rule is, when a built-in basic type, unsafe.Pointer
or a non-defined type is met, the tracing will be stopped.
Take the type declarations above as examples, let's trace their underlying types.
MyInt → int Age → MyInt → int IntSlice → []int MyIntSlice → []MyInt →[]intAgeSlice → []Age →[]MyInt→[]intAges → AgeSlice → []Age →[]MyInt→[]int
In Go,
bool
are called boolean types;float32
or float64
are called floating-point types;complex64
or complex128
are called complex types;string
are called string types.The concept of underlying type plays an important role in value conversions, assignments and comparisons in Go.
An instance of a type is called a value, of the type. A type may have many values, one of them is the zero value of the type. Values of the same type share some common properties.
Each type has a zero value, which can be viewed as the default value of the type.
The predeclared nil
identifier can used to represent as
zero values of slice, map, function, channel,
pointer (including type-unsafe pointer) and interface types.
About more on nil
, please read nil in Go later.
There are several kinds of value representation forms in code, including literals, named constants, variables and expressions, though the former three can be viewed as special cases of the latter one.
Value may be typed or untyped.
All kinds of basic value literals have been introduced in in the article basic types and basic value literals. There are two more kinds of literals in Go, composite literals and function literals.
Function literals, as the name implies, are used to represent function values. A function declaration is composed of a function literal and an identifier (the function name).
Composite literals are used to represent values of struct types and container types (arrays, slices and maps), Please read structs in Go and containers in Go for details.
There are no literals to represent values of pointer, channel and interface types.
At run time, many values are stored somewhere in memory. In Go, each of such values has a direct part, however, some of them have one or more indirect parts. Each value part occupies a continuous memory segment. The indirect underlying parts of a value are referenced by its direct part through pointers.
The terminology value part is not defined in Go specification. It is just used in Go 101 to make some explanations simpler and help Go programmers understand Go types and values better.
When a value is stored in memory, the number of bytes occupied by the direct part of the value is called the size of the value. All values of the same type have the same value size, so the size of values of a type is often called as the size, or value size, of the type.
We can use the Sizeof
function in the unsafe
standard package to get the size of any value.
Go specification doesn't specify values size requirements for non-numeric types. The requirements for value sizes of all kinds of basic numeric types are listed in the article basic Types and basic value literals.
For a pointer type, assume its underlying type can be denoted as *T
in literal, then T
is called the base type of the pointer type.
For more about pointer types and values, please read pointers in Go.
Book
has
three fields, author
, title
and pages
.
struct {
author string
title string
pages int
}
For more about struct types and values, please read structs in Go.
The signature of a function type is composed of the input parameter definition list and the output result definition list of the function.
The function name and body are not parts of a function signature. Parameter and result types are important for a function signature, but parameter and result names are not important.
Please read functions in Go for more details about function type and function values.
In Go, some types can have methods. Methods can also be called member functions. The method set of a type is composed of all the methods of the type.
Interface values are the values whose types are interface types.
Each interface value can box a non-interface value in it. The value boxed in an interface value is called the dynamic value of the interface value. The type of the dynamic value is called the dynamic type of the interface value. An interface value boxing nothing is a zero interface value. A zero interface value has not dynamic value and dynamic type.
An interface type can specified zero or several methods, which form the method set of the interface type.
If the method set of a type, which is either an interface type or a non-interface type, is the super set of the method set of an interface type, we say the type implements the interface type.
For more about interface types and values, please read this article.
For a (typed) non-interface value, its concrete value is itself and its concrete type is the type of the value.
A zero interface value has neither concrete type nor concrete value. For a non-zero interface value, its concrete value is its dynamic value and its concrete type is its dynamic type.
Array, slice and map can be viewed as formal container types.
Sometimes, string and channel types can also be viewed as container types informally.
Each value of a container type has a length, either that container type is a formal one or an informal one.
For more about formal container types and values, please read containers in Go.
If the underlying type of a map type can be denoted as map[Tkey]T
,
then Tkey
is called the key type of the map type.
Tkey
must be a comparable type (see below).
[N]T
, then its element type is T
.[]T
, then its element type is T
.map[Tkey]T
, then its element type is T
.chan T
, chan<- T
or <-chan T
, then its element type is T
.byte
(a.k.a. uint8
).chan T
in literal.
chan<- T
in literal.
<-chan T
in literal.
For more about channel types and values, please read channels in Go.
==
and !=
operators):
Above listed types are called uncomparable types. All other types are called comparable types. Compilers forbid comparing two values of uncomparable types.
Note, some Go tools may call uncomparable types as incomparable types.
The key type of any map type must be a comparable type.
We can learn more about the detailed rules of comparisons from the article value conversions, assignments and comparisons in Go.
Up to now (Go 1.12), the generic functionalities in Go are limited to built-in types and functions. Custom generics are still in draft phase now. Please read built-in generics in Go for details.