Примитивные типы данных
В языке Rust имеются такие примитивные типы данных.
Целочисленные типы
| Размер | Знаковый | Беззнаковый |
|---|---|---|
| 8 бит | i8 | u8 |
| 16 бит | i16 | u16 |
| 32 бита | i32 | u32 |
| 64 бита | i64 | u64 |
| 128 бит | i128 | u128 |
| Платформозависимый (равный размеру указателя) | isize | usize |
Если мы объявляем переменную без указания типа и инициализируем её целым числом, то по умолчанию используется тип i32. Если же мы инициализируем переменную числом с плавающей запятой, то по умолчанию используется тип f64.
#![allow(unused)]
fn main() {
let a = 5; // i32
let b = 5.0; // f64
}
Тип числа можно указывать как явно, так и при помощи суффикса к инициализирующему значению:
#![allow(unused)]
fn main() {
let a: u8 = 5;
let b = 5u8;
let c: f32 = 5.0;
let d = 5.0f32;
let e: u128 = 1;
let f = 1u128;
}
Числа с плавающей запятой
Для представления чисел с плавающей запятой в Rust имеется два типа: f32 и f64. Соответственно, их размер 32 и 64 бита.
Оба типа реализуют стандарт IEEE-754, то есть значения типов f32 и f64 могут хранить как вещественные числа, так и “бесконечность” и “не число”.
#![allow(unused)]
fn main() {
let a: f32 = -1.0; // 1.0
let b = 5.0f32; // 5.0
let c = a + b; // 4.0
let d = 1.0 / 0.0; // inf
let e = a.sqrt(); // NaN
}
bool
Булевый тип в Rust ровно такой, каким его можно ожидать: может хранить либо true, либо false.
#![allow(unused)]
fn main() {
let a: bool = true;
let b = false;
}
Значение типа bool занимает в оперативной памяти 1 байт.
Символы
Для хранения отдельных текстовых символов используется тип char. Фактически это 4-байтное число, хранящее код символа в таблице Unicode.
Rust позволяет указать символ в исходном коде программы, как текстовый знак, взятый в одинарные кавычки.
#![allow(unused)]
fn main() {
let a = 'a';
let smile = '☺';
let book = '本';
}
Unit
Тип Unit — аналог типа void в C, Java и других им подобных языках. Как правило, он используется для обозначения типа результата в функциях, которые не возвращают какое-либо значение.
Хоть тип и называется “Unit”, в коде он обозначается как () .
Принципиальное отличие типа Unit, являющегося множеством-синглтон, от типа void, который представляет пустое множество, заключается в том, что у типа Unit есть одно единственное значение —(). Мы можем даже создать переменную типа Unit и присвоить ей () .
#![allow(unused)]
fn main() {
let a: () = ();
}
Tip
Чем не подходит void? Тип Unit появился в языках, которые испытали на себе влияние функционального программирования. Дело в том, что в функциональном программировании функция рассматривается, в первую очередь, как математическая функция, т.е. отображение значения из множества аргументов в значение из множества результатов. Здесь и появляется фундаментальная проблема типа
void: это пустое множество, в котором нет значений. Это сильно усложняет моделирование системы типов для таких важных в функциональном программировании операций, как композиция функций.В чисто функциональном языке Haskell даже имеется специальная функция
absurd, которая принимает аргумент типа Void и возвращает некое значение.absurd :: Void -> aКакое это значение и какого оно типа — не важно, так как эту функцию невозможно вызвать, ведь для её вызова необходим элемент из пустого множества Void, а такой не существует.
Never type
Еще один интересный тип, обусловленный особенностями системы типов данных в языках, испытавших воздействие функционального программирования, — never type.
В коде этот тип обозначается как !
Этот тип практически никогда не указывается явно и даже не наблюдается в коде. Более того, если не знать о его наличии, то можно годами писать на Rust и даже не подозревать о его существовании.
На данном этапе мы пока что не сможем разобраться с этим типом. Скажем только, что компилятор использует этот тип для выражений, которые никогда не возвращают значение в вызывающий код. Например, для функции выхода из программы.
Мы подробнее рассмотрим never type в главе Функции.
Приведение типов
Для того чтобы преобразовать один тип данных в другой, используется оператор as.
Синтаксис:
значение as Тип
Пример:
fn main() {
let a: i32 = 5;
let b: i64 = a as i64;
let c: i32 = b as i32;
let d: f32 = 7.0;
let e: i32 = d as i32;
let f: bool = true;
let g: i32 = f as i32; // 1
let h = false as i32; // 0
let i = 'A' as i32; // 65
let j = 66 as char; // B
}
Rust является языком со строгой типизацией, поэтому в нём отсутствуют неявные преобразования типов, как в C. Любое преобразование типов нужно указывать явно при помощи оператора as.