Rust на примерах — страница 9 из 65

println!("Перед изменением: {}", mutable_binding);

// Ok

mutable_binding += 1;

println!("После изменения: {}", mutable_binding);

// Ошибка!

_immutable_binding += 1;

// ИСПРАВЬТЕ ^ Закомментируйте эту строку

}

הההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההה

XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Компилятор будет выводить подробные сообщения об ошибках, связанных с изменяемостью.

Область видимости и затенение

Связывание переменных имеет локальную область видимости, и живут эти переменные в блоке. Блок — набор инструкций, заключённый между фигурными скобками {}. Кроме того, допускается затенение переменных.

fn main() {

// Эта переменная живёт в функции main

let long_lived_binding = 1;

// Это блок, он имеет меньшую область видимости, чем функция main

{

// Эта переменная существует только в этом блоке

let short_lived_binding = 2;

println!("inner short: {}", short_lived_binding);

// Эта переменная *затеняет* собой внешнюю

let long_lived_binding = 5_f32;

println!("inner long: {}", long_lived_binding);

}

// Конец блока

// Ошибка! `short_lived_binding` нет в этой области видимости

println!("outer short: {}", short_lived_binding);

// ИСПРАВЬТЕ ^ Закомментируйте строку

println!("outer long: {}", long_lived_binding);

// Это связывание так же *скрывает* собой предыдущие

let long_lived_binding = 'a';

println!("outer long: {}", long_lived_binding);

}

הההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההה

XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Предварительное объявление

Можно сначала объявить связь с переменной, а инициализировать её позже. Однако, такая форма используется редко, так как может привести к использованию неинициализированных переменных.

fn main() {

// Объявляем связь с переменной

let a_binding;

{

let x = 2;

// Инициализируем связь

a_binding = x * x;

}

println!("связь а: {}", a_binding);

let another_binding;

// Ошибка! Использование неинициализированной связи с переменной

println!("другая связь: {}", another_binding);

// ИСПРАВЬТЕ ^ Закомментируйте строку

another_binding = 1;

println!("другая связь: {}", another_binding);

}

הההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההה

XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Компилятор запрещает использование неинициализированных переменных, так как это привело бы к неопределённому поведению.

ЗаморозкаТипы

Rust предоставляет несколько механизмов изменения или определения примитивных и пользовательских типов:

   • Приведение между примитивными типами

   • Указание желаемого типа при помощи литералов

   • Использование вывода типов

   • Псевдонимы типов

Приведение типов

Rust не предусматривает неявного преобразования типов (принудительное) между примитивными типами. Но, явное преобразование типов (casting) можно выполнить используя ключевое слово as.

Правила, используемые для преобразование внутренних типов, такие же, как в языке C, за исключением тех случаев, когда преобразование типов в языке C вызывает неопределённое поведение. Поведение всех приведений между встроенными типами чётко определено в Rust.

// Убрать все предупреждения

// которые вызываются переполнением при преобразование типов.

#![allow(overflowing_literals)]

fn main() {

let decimal = 65.4321_f32;

// Ошибка! Нет неявного преобразования

let integer: u8 = decimal;

// ИСПРАВЬТЕ ^ Закомментируйте данную строку

// Явное преобразование

let integer = decimal as u8;

let character = integer as char;

// Ошибка! Здесь ограничение в правилах конвертации. Число с плавающей точкой не может быть напрямую конвертирован в символ.

let character = decimal as char;

// ИСПРАВЬТЕ ^ Закомментируйте данную строку

println!("Casting: {} -> {} -> {}", decimal, integer, character);

// Когда преобразовывается любое значение в беззнаковый тип T

// std::T::MAX + 1 добавляется или вычитается до тех пор, пока значение

// не будет помещаться в новый тип.

// 1000 поместится в u16

println!("1000 as a u16 is: {}", 1000 as u16);

// 1000 - 256 - 256 - 256 = 232

// Подробнее. Первые 8 младших битов (LSB) сохраняются,

// а старшие биты (MSB) будут усечены.

println!("1000 as a u8 is : {}", 1000 as u8);

// -1 + 256 = 255

println!("  -1 as a u8 is : {}", (-1i8) as u8);

// Для положительных чисел результатом будет остаток от деления

println!("1000 mod 256 is : {}", 1000 % 256);

// Когда значение преобразовывается в знаковый тип,

// побитовый результат будет таким же, как и

// первое преобразование к соответствующему типу без знака. Если старший бит этого значения

// равен 1, то это значение отрицательное.

// За исключением случая, когда значение умещается в тип.

println!(" 128 as a i16 is: {}", 128 as i16);