Введение
Добро пожаловать, Gophers, в эту новую главу. В этом разделе мы изучим числовые типы. Содержание включает в себя часто используемые целочисленные типы (integer types), типы с плавающей точкой (floating-point types), логические типы (boolean types), а также комплексные числа и синтаксис литеральных значений (literal value syntax), представленный в версии 1.13.
Ключевые моменты:
- Целочисленные типы (Integer types)
- Типы с плавающей точкой (Floating-point types)
- Логические типы (Boolean types)
- Комплексные числа (Complex numbers)
- Синтаксис литеральных значений (Literal value syntax)
Целые числа (Integers)
Целые числа можно разделить на две категории: беззнаковые целые числа (unsigned integers) и знаковые целые числа (signed integers). Знаковые целые числа используются наиболее широко.
Беззнаковое (Unsigned) означает, что оно может представлять только неотрицательные числа (0 и положительные числа), в то время как знаковые числа (signed numbers) могут представлять как отрицательные, так и неотрицательные числа.
Беззнаковые целые числа можно разделить на четыре размера: 8 бит, 16 бит, 32 бита и 64 бита, представленные соответственно uint8, uint16, uint32 и uint64. Соответствующие знаковые целые числа: int8, int16, int32 и int64. В следующей таблице показаны различные диапазоны, представленные каждым типом:
| Тип | Описание | Диапазон |
|---|---|---|
| uint8 | 8-битное беззнаковое int | от 0 до 255 |
| int8 | 8-битное знаковое int | от -128 до 127 |
| uint16 | 16-битное беззнаковое int | от 0 до 65535 |
| int16 | 16-битное знаковое int | от -32768 до 32767 |
| uint32 | 32-битное беззнаковое int | от 0 до 4294967295 |
| int32 | 32-битное знаковое int | от -2147483648 до 2147483647 |
| uint64 | 64-битное беззнаковое int | от 0 до 18446744073709551615 |
| int64 | 64-битное знаковое int | от -9223372036854775808 до 9223372036854775807 |
Возьмем в качестве примера uint8 и int8. Они оба являются 8-битными целыми числами и могут представлять 256 значений. В беззнаковом целочисленном типе uint8 диапазон, который он может представлять, составляет от 0 до 255, в то время как в знаковом целочисленном типе int8 диапазон, который он может представлять, составляет от -128 до 127.
В дополнение к вышеуказанным 8 типам существуют три других специальных целочисленных типа: uint, int и uintptr, где uint и int могут представлять разные диапазоны на разных платформах, а uintptr используется для хранения адресов указателей (pointer addresses).
| Тип | Диапазон |
|---|---|
uint |
uint32 в 32-битных системах, uint64 в 64-битных системах |
int |
int32 в 32-битных системах, int64 в 64-битных системах |
uintptr |
Беззнаковый целочисленный тип, используемый для хранения адресов указателей (pointer addresses), в основном используется в низкоуровневом программировании, таком как небезопасные операции (unsafe operations) |
Теперь давайте создадим файл с именем integer.go, чтобы продемонстрировать использование целых чисел:
cd ~/project
touch integer.go
package main
import (
"fmt"
"unsafe"
)
func main() {
// View the type of int in the current environment
// Declare a as the type int
var a int
// Use unsafe.Sizeof() to output the memory size occupied by the type
fmt.Printf("The type int in the current environment is %d bits\n", unsafe.Sizeof(a)*8)
var b int8 = 125
// Use the %d placeholder in fmt.Printf to output the value of the integer
// Use the %T placeholder in fmt.Printf to output the type of the variable
fmt.Printf("The value of b is %d, and the type is %T\n", b, b)
// Integer operations
// Declare integers c and d, and calculate their sum
c, d := 2, 3
fmt.Printf("c + d = %d\n", c+d)
// 10 - 5
fmt.Printf("10 - 5 = %d\n", 10-5)
// 8 * 10
fmt.Printf("8 * 10 = %d\n", 8*10)
// Example of uintptr usage - storing an address
var ptr uintptr
x := 42
// Convert the pointer to x to uintptr
ptr = uintptr(unsafe.Pointer(&x))
fmt.Printf("The address of x stored in ptr is: %v\n", ptr)
}
После выполнения программы мы получим следующий вывод:
go run integer.go
The type int in the current environment is 64 bits
The value of b is 125, and the type is int8
c + d = 5
10 - 5 = 5
8 * 10 = 80
The address of x stored in ptr is: 824634818784
Объяснение вывода:
The type int in the current environment is 64 bits: Эта строка показывает, что типintв системе, где выполняется код, составляет 64 бита (или 8 байт), что указывает на то, что этоint64.unsafe.Sizeof(a)возвращает размер переменнойaв байтах, а умножение на 8 преобразует его в биты. Это означает, что типintможет содержать большие целочисленные значения.The value of b is 125, and the type is int8: Здесь мы объявили переменнуюbтипаint8и присвоили ей значение 125. Вывод подтверждает это, показывая как значение, так и тип данных.c + d = 5,10 - 5 = 5,8 * 10 = 80: Эти строки демонстрируют основные арифметические операции с целыми числами: сложение, вычитание и умножение. Вывод подтверждает правильные результаты этих вычислений.The address of x stored in ptr is: 824634818784: Это демонстрирует, какuintptrможно использовать для хранения адреса памяти. Мы преобразуем указатель на целочисленную переменнуюxв типuintptr. Фактическое значение адреса будет меняться каждый раз при запуске программы. Это продвинутый вариант использования, обычно встречающийся в небезопасных операциях (unsafe operations) и системном программировании.
В этом файле функция unsafe.Sizeof() может использоваться для получения количества байтов, занимаемых текущим типом переменной. 1 байт (byte) равен 8 битам, поэтому unsafe.Sizeof()*8 может получить количество битов, занимаемых типом. Из вывода мы видим, что онлайн-среда составляет 64 бита. Фактический тип int в онлайн-среде — int64.
Мы можем использовать следующую команду в терминале, чтобы определить текущую архитектуру системы:
dpkg --print-architecture
amd64
Числа с плавающей точкой (Floating-Point Numbers)
Числа с плавающей точкой (floating-point numbers) представляют вещественные числа с дробными частями в Go, используя два типа: float32 и float64. Типом с плавающей точкой по умолчанию является float64.
float32 и float64 представляют различную точность (precision). Точность float64 по умолчанию выше, чем у float32.
Стандарт IEEE 754 является наиболее широко используемым стандартом вычислений с плавающей точкой в компьютерах, и современные процессоры (CPU) все поддерживают этот стандарт. Как и другие языки программирования, Go также использует IEEE 754 для хранения чисел с плавающей точкой.
Мы знаем, что байт (byte) в компьютере может хранить 8 бит. float32 — это число с плавающей точкой одинарной точности (single-precision floating-point number) и занимает 4 байта, что составляет 32 бита. float64 — это число двойной точности (double-precision) и занимает 8 байт, что составляет 64 бита.
В float32 знаковый бит (sign bit) занимает 1 бит, экспонента (exponent) занимает 8 бит, а оставшиеся 23 бита используются для представления мантиссы (mantissa).
В float64 знаковый бит также занимает 1 бит, экспонента занимает 11 бит, а оставшиеся 52 бита используются для представления мантиссы.
Максимальное значение, которое может представлять float32, составляет приблизительно 3.4e+38 в научной нотации (scientific notation), а минимальное значение — 1.4e-45. Максимальное значение, которое может представлять float64, составляет приблизительно 1.8e+308, а минимальное значение — 4.9e-324. Мы видим, что диапазон значений с плавающей точкой может быть от очень малого до очень большого.
Мы можем использовать константу math.MaxFloat32 для представления максимального значения в float32. Используйте константу math.MaxFloat64 для представления максимального значения в float64.
Представление чисел с плавающей точкой
При выводе чисел с плавающей точкой мы можем использовать заполнитель %f функции Printf пакета fmt. Вот пример:
cd ~/project
touch float.go
package main
import (
"fmt"
"math"
)
func main() {
// Output without exponential form
fmt.Printf("2.333 without exponential form: %f\n", 2.333)
fmt.Printf("Pi without exponential form: %f\n", math.Pi)
// Use %.2f to keep two decimal places for Pi
fmt.Printf("Pi with two decimal places: %.2f\n", math.Pi)
fmt.Printf("The maximum value of float32: %f\n", math.MaxFloat32)
// Exponential form
fmt.Printf("2.333 in exponential form: %e", 2.333)
}
Запустите команду, и вы увидите следующий вывод.
go run float.go
2.333 without exponential form: 2.333000
Pi without exponential form: 3.141593
Pi with two decimal places: 3.14
The maximum value of float32: 340282346638528859811704183484516925440.000000
2.333 in exponential form: 2.333000e+00
Объяснение вывода:
2.333 without exponential form: 2.333000: Это показывает число2.333, напечатанное с использованием заполнителя%f. По умолчанию заполнитель%fпоказывает 6 цифр после десятичной точки, поэтому2.333становится2.333000.Pi without exponential form: 3.141593: Эта строка печатает значение константыmath.Pi, которая является приближением математической константы π. Заполнитель%fотображает ее с полной точностью.Pi with two decimal places: 3.14: Используя%.2f, мы указываемfmt.Printfотформатировать число до двух цифр после десятичной точки, что приводит к3.14. Это очень полезно, когда вам нужна только определенная точность для вывода.The maximum value of float32: 340282346638528859811704183484516925440.000000: Это показывает максимальное значение, которое может представлятьfloat32. Обратите внимание, что это очень большое число, и при печати с%fоно будет представлено множеством цифр.2.333 in exponential form: 2.333000e+00: Эта строка показывает, как представить число с плавающей точкой в экспоненциальной (научной) нотации (exponential (scientific) notation) с использованием заполнителя%e.e+00в конце указывает, что мы умножаем2.333000на 10 в степени 0, что просто2.333. Если бы экспонента былаe+02, то число было бы умножено на10^2(100), что привело бы к233.3.
Логические типы (Boolean Types)
Тип bool имеет только два возможных значения: true или false, причем false является значением по умолчанию. Он имеет следующие характеристики:
- Его нельзя преобразовать в другие типы, например, преобразовать целое число в логическое или преобразовать логическое значение в целое число.
- Он не может участвовать в арифметических операциях.
Логические типы обычно используются в сочетании с операторами отношения (relational operators), такими как =, >, и <. Давайте создадим файл с именем bool.go, чтобы увидеть демонстрацию:
cd ~/project
touch bool.go
package main
import (
"fmt"
)
func main() {
// Use the %t placeholder in fmt.Printf to represent a boolean value
fmt.Printf("Is 3 equal to 2? %t\n", 3 == 2)
fmt.Printf("Is 2 equal to 2? %t\n", 2 == 2)
// Determine whether a and b are equal
a, b := 1, 2
fmt.Printf("a is %d, b is %d\n", a, b)
if a > b {
fmt.Println("a is greater than b")
} else if a == b {
fmt.Println("a is equal to b")
} else {
fmt.Println("b is greater than a")
}
}
После запуска программы мы получим следующий вывод:
go run bool.go
Is 3 equal to 2? false
Is 2 equal to 2? true
a is 1, b is 2
b is greater than a
Объяснение вывода:
Is 3 equal to 2? false: Выражение3 == 2вычисляется какfalse, которое затем выводится с использованием заполнителя%t.Is 2 equal to 2? true: Выражение2 == 2вычисляется какtrue, которое затем выводится с использованием заполнителя%t.a is 1, b is 2: Эта строка выводит присвоенные значения целочисленных переменныхaиb.b is greater than a: Условный операторif-else if-elseвычисляется какa < b, что равно1 < 2(истина), поэтому выполняется операторelse, в результате чего программа печатает "b is greater than a".
В этой программе мы сначала используем %t в fmt.Printf для представления логического значения, а затем используем оператор if для определения взаимосвязи между двумя значениями. В fmt.Printf мы можем использовать заполнитель %d для представления целого числа, заполнитель %f для представления числа с плавающей точкой и заполнитель %t для представления логического значения.
Комплексные числа (Complex Numbers)
Go также имеет встроенные типы комплексных чисел (complex number types), которые можно разделить на типы complex64 и complex128. В complex64 как действительная (real), так и мнимая (imaginary) части являются 32-битными, в то время как в complex128 как действительная, так и мнимая части являются 64-битными. Мы можем легко выполнять операции с комплексными числами в Go.
Создайте файл с именем complex.go и введите следующий код:
cd ~/project
touch complex.go
package main
import (
"fmt"
)
func main() {
// Initialize complex numbers in different ways
c1 := complex(3, 1)
c2 := 4 + 5i
// Complex number operations
c3 := c1 + c2
c4 := c1 * c2
// Use the real() function to obtain the real part of a complex number, and the imag() function to obtain the imaginary part of a complex number
fmt.Printf("The real part of c1 is %v, the imaginary part is %v\n", real(c1), imag(c1))
// %v in fmt.Printf can be used to represent complex numbers
fmt.Printf("c1 + c2 is %v\n", c3)
fmt.Printf("c1 * c2 is %v\n", c4)
}
После запуска программы мы получим следующий вывод:
go run complex.go
The real part of c1 is 3, the imaginary part is 1
c1 + c2 is (7+6i)
c1 * c2 is (7+19i)
Объяснение вывода:
The real part of c1 is 3, the imaginary part is 1: Функцияreal(c1)извлекает действительную часть (real part) комплексного числаc1, которая равна3, аimag(c1)извлекает мнимую часть (imaginary part)c1, которая равна1. Эти значения затем выводятся с использованием заполнителя%v.c1 + c2 is (7+6i): Эта строка показывает результат сложения комплексных чиселc1иc2.c1определено как3 + 1i, аc2как4 + 5i. Сложение действительных и мнимых частей по отдельности дает(3 + 4) + (1 + 5)i, или7 + 6i.c1 * c2 is (7+19i): Эта строка показывает результат умножения комплексных чиселc1иc2.(3 + 1i) * (4 + 5i)вычисляется как(3*4 - 1*5) + (3*5 + 1*4)i, что упрощается до(12-5) + (15+4)i, и, наконец, до7+19i.
В этой программе мы продемонстрировали, как инициализировать и выполнять операции над комплексными числами с использованием функции complex и операторов + и *. real() и imag() используются для извлечения действительной и мнимой частей комплексного числа соответственно. Глагол %v в fmt.Printf используется в качестве общего заполнителя для отображения комплексных чисел.
Синтаксис литеральных значений (Literal Value Syntax)
В версии 1.13 Go представил Numeric Literal Syntax (синтаксис числовых литералов). Он определяет представление чисел в различных системах счисления. Давайте рассмотрим его правила.
- Двоичная (Binary): Добавьте
0bперед целым числом. Например,0b101эквивалентно5в десятичной системе. - Восьмеричная (Octal): Добавьте
0oили0Oперед целым числом. Например,0o11эквивалентно9в десятичной системе. - Шестнадцатеричная (Hexadecimal): Добавьте
0xили0Xперед целым числом. Например,0x1bэквивалентно27в десятичной системе. - Используйте
_для разделения цифр в целых числах, например,0b1000_0100_0010_0001эквивалентно0b1000010000100001. Это может улучшить читаемость.
Давайте продемонстрируем это подробно:
cd ~/project
touch literals.go
package main
import "fmt"
func main() {
// Binary, add 0b at the beginning
var a int = 0b101
fmt.Printf("Binary a is %b, decimal is %d\n", a, a)
// Octal, add 0o or 0O at the beginning
var b int = 0o11
fmt.Printf("Octal b is %o, decimal is %d\n", b, b)
// Hexadecimal, add 0x or 0X at the beginning
var c int = 0x1b
fmt.Printf("Hexadecimal c is %x, decimal is %d\n", c, c)
// Use separators
d := 0b1000_0100_0010_0001
e := 0b1000010000100001
if d == e {
fmt.Println("d is equal to e")
}
}
После запуска программы мы получим следующий вывод:
go run literals.go
Binary a is 101, decimal is 5
Octal b is 11, decimal is 9
Hexadecimal c is 1b, decimal is 27
d is equal to e
Объяснение вывода:
Binary a is 101, decimal is 5: Эта строка показывает двоичное представление0b101, которое равно101, а его десятичный эквивалент равен5. Заполнитель%bотображает двоичное значениеa, а%dотображает десятичное представление.Octal b is 11, decimal is 9: Восьмеричное число0o11эквивалентно1*8^1 + 1*8^0 = 8 + 1 = 9в десятичной системе. Заполнитель%oотображает восьмеричное представлениеb, а%dотображает его десятичное значение.Hexadecimal c is 1b, decimal is 27: Шестнадцатеричное число0x1bэквивалентно1*16^1 + 11*16^0 = 16 + 11 = 27в десятичной системе. Заполнитель%xотображает шестнадцатеричное представлениеc, а%dотображает его десятичное значение.d is equal to e: Это показывает, что двоичный литерал (binary literal)0b1000_0100_0010_0001равен0b1000010000100001по значению. Подчеркивания используются исключительно для читаемости и не изменяют значение числа. Условиеifправильно вычисляется какtrue.
В этой программе мы продемонстрировали объявление и вывод различных систем счисления, а также использование разделителей. В fmt.Printf мы использовали разные заполнители для представления разных систем счисления. Например, %b представляет двоичную систему, а %x представляет шестнадцатеричную систему. Освоение их повысит эффективность программирования.
Резюме
Давайте повторим, что мы изучили в этом разделе:
- Целые числа (integers) можно разделить на знаковые (signed integers) и беззнаковые (unsigned integers)
- Диапазоны типов целых чисел
intиuintпо умолчанию зависят от платформы - Представление чисел с плавающей точкой (floating-point numbers)
- Как использовать комплексные числа (complex numbers)
- Введение в синтаксис литеральных значений (literal value syntax)
- Как использовать различные заполнители (placeholders)
В этом разделе мы объяснили и продемонстрировали распространенные типы целых чисел, типы с плавающей точкой и логические типы (boolean types). Мы обсудили их размеры, диапазоны и использование. Мы также представили комплексные числа и литеральные константы (literal constants). Числовые типы являются краеугольным камнем программ Go, и учащимся важно хорошо их изучить.



