为什么Go有几种不同的整数类型?

I find it rather confusing that there are different integer types in Go. What is the necessity of defining these different categories, given that these distinctions are not present in many other major programming languages?

int  int8  int16  int32  int64
uint uint8 uint16 uint32 uint64 uintptr

The C99 language has a similar classification thru <stdint.h> (and C is even more fine-grained, with types like int_fast32_t) ; having that many integral types is useful for portability and efficiency.

Compatibility with C99 & C++ may be enough a reason for Go to have these types.

You may want to write code which can efficiently run on embedded microcontrollers, tablets (32 bits ARM), cheap laptops (32 bits x86), bigger desktops (64 bits x86-64), servers (perhaps also PowerPC or 64 bits AARCH64 ARM), etc... And you have various programming models or ABIs on some operating systems (e.g. x86, x32, amd64 on my Linux desktop).

On various architectures, the cost of integral operations may vary greatly. On some machines, adding an int might be more costly than adding a C long (or an int64 from Go). On other machines (probably most of them), it might be the opposite. And CPU cache considerations could matter a lot w.r.t. performance. And in some cases (e.g. if you have billion-sized array) data size matters a lot. At last, for binary data coming from outside, size, layout, alignment, and endianness matter a lot. Read about serialization.

Why does Go have several different types at all? To work with different type/kind of data.

Why does Go have several different integer types? To work with different type/kind of integer data.

There are even more which you haven't listed:

byte    alias for uint8
rune    alias for int32

The distinction between signed and unsigned is pretty obvious. In Java there are no unsigned integers and I find it more confusing than to have extra types and have the convenience to choose. In Java to write applications that inter-operate with other systems which send/receive unsigned integer data is just annoying.

Regarding the bit-size, you have the convenience to choose that best suits your memory needs (or memory strictness) and also to restrict the possible range of the values your variable represents. Without adding complexity to the language or to your program.

The "palette" to choose bit-size of integer variables is not exhausting whatsoever, most other languages provide the same range of integer types. If you exclude sign-ness, then Java basically has the same amount:

Java         Go
-------------------------
byte    =>   int8
short   =>   int16
int     =>   int32
long    =>   int64

Go has two kinds of types:

  1. architecture dependent types such as int, uint, uintptr. and
  2. architecture independent types such as int32, int64 etc.

The architecture dependent types have the appropriate length for the machine on which the program runs:

  • an int is the default signed type: it takes 32 bit (4 bytes) on a 32 bit machine and 64 bit (8 bytes) on a 64 bit machine; the same goes for the unsigned uint.
  • uintptr is an unsigned integer large enough to store a pointer value.

The architecture independent types have fixed size (in bits) indicated by their names:

For integers the ranges are:

int8 (-128 -> 127)
int16 (-32768 -> 32767)
int32 (− 2,147,483,648 -> 2,147,483,647)
int64 (− 9,223,372,036,854,775,808 -> 9,223,372,036,854,775,807)

For unsigned integers:

uint8 (with alias byte, 0 -> 255)
uint16 (0 -> 65,535)
uint32 (0 -> 4,294,967,295)
uint64 (0 -> 18,446,744,073,709,551,615)

For floats:

float32 (+- 1O-45 -> +- 3.4 * 1038 )
(IEEE-754) float64 (+- 5 * 10-324 -> 1.7 * 10308 )

int is the integer type which offers the fastest processing speeds. The initial (default) value for integers is 0, and for floats this is 0.0 A float32 is reliably accurate to about 7 decimal places, a float64 to about 15 decimal places.

Due to the fact that perfect accuracy is not possible for floats comparing them with == or != must be done very carefully!

The existing answers are correct. Let me offer a different perspective.

Asking this question implies that you are used to languages that are higher level than Go. Languages like Python can be seen as providing a single integer type with unlimited precision. This isn't true internally, but in practice you can write your code assuming that it is true.

Go is not that kind of language. The language proper does not offer an integer type with unlimited precision (there is one available in the math/big package). Instead, each integer type has a specific size, and operations that yield integers that do not fit in that size wrap. So, in Go, uint32(0xffffffff) + uint32(1) == uint32(0).

Go works this way because the resulting code is, in general, more efficient. It also permits Go programmers to write struct types that can be stored in memory more efficiently. However, it does mean that a programmer working with large numbers has to be aware of the possibility of overflow.