What is the memory implication of storing an integer as a particular numeric type (uint8, int16, uint32, int64, etc)? I know the range of integers each of the types can take, but is there some memory efficiency that can be achieved by using an appropriate type?
For example, in Golang, it "seems" more efficient to store someone's age as an uint8 rather than unit (which is equivalent to uint32 or uint64 according to its specification https://golang.org/ref/spec#Numeric_types)
Fixed size integers require exact amount of memory. Using a smaller integer type "here and there" for single variables, you will only gain a tiny amount of memory, if any. Also when used as types of struct fields, you again might not gain anything due to implicit paddings.
The memory gain may be noticeable and considerable when you use fixed size integers as the element type of (big) slices or arrays.
Another (maybe more important) reason to use fixed size integers may be to communicate what you store in them. You could just as well use int32
or int64
type to store bytes, but being an obvious waste, they don't communicate the valid range of the data stored in them.
Another point is efficiency. You could always use int64
in place of other signed integer types, but on certain architectures performing operations on int64
might require multiple register operations and thus being considerably slower. Also the rune
type (alias for int32
) clearly communicates that you intend to use it for unicode codepoints.
Another point is consistency. If you use int32
to model something in one place, you should stick to it and use the same type everywhere. This is more important in Go than in other languages, because Go's type system is strict (stricter than most other language's), meaning if you have a value of type int32
, you can't assign it to a variable of int64
type and vice versa without explicit conversion.
int
vs fixed size integersThe types int
and uint
are not fixed sizes, but according to Spec: Numeric types:
uint either 32 or 64 bits int same size as uint
When you use int
, the compiler may produce more optimized code when targeting different architectures. Usually int
is 32-bit when targeting 32-bit architectures, and 64-bit when targeting 64-bit architectures. What this means is that the size of int
will match the target architecture's register size, so integer operations can be efficiently carried out with single register operations. If you use int64
for example, that may require to perform multiple (register) operations to carry out a single integer operation on a 32-bit architecture.
I like to think of int
being an integer type that is used to describe and communicate certain parts or components of Go's runtime data structures in the best way it sees fits. For example to index arrays or slices, or to describe their sizes, int
is the "natural" type to use.
The built-in functions
len
andcap
take arguments of various types and return a result of typeint
. The implementation guarantees that the result always fits into anint
. For example indexing slices or array, or to describe their length and capacity,int
is the "natural" type recommended or enforced.
When using the for range
statement with at least one iteration variable on arrays, slices or string
values, the iteration variable (the "index") will be of type int
.
Also note that a proposal has been presented by Rob Pike for Go 2 to change int
to arbitrary precision. proposal: spec: change int to be arbitrary precision
1) Fixed size integers can be used to reduce the memory used by your application. In a 3D app for example it can make more sense to use float32
rather than float64
because the graphics card wants float32
s anyway and to use uint16
rather than uint32
for draw indices for example.
That said, for single variables it makes no difference, only if you have a large number of values and can trade precision for memory.
2) When writing to disk, e.g. using the encoding/binary package, you cannot use int
or uint
because their size changes between operating systems. You have to use values of known size to make the file format unambiguous.
3) When interfacing with the operating system's API it is often required to use fixed-size variables. For example, the Windows API is a 32 bit API which means that when you load a Windows DLL you often need to use 32 bit unsigned integers for flags etc.