Приведение типов в Rust: явное преобразование типов

RustRustBeginner
Практиковаться сейчас

This tutorial is from open-source community. Access the source code

💡 Этот учебник переведен с английского с помощью ИИ. Чтобы просмотреть оригинал, вы можете перейти на английский оригинал

Введение

В этом лабе мы узнаем о приведении типов в Rust и о том, как выполнять явное преобразование типов с использованием ключевого слова as.

Примечание: Если в лабе не указано имя файла, вы можете использовать любое имя файла, которое хотите. Например, вы можете использовать main.rs, скомпилировать и запустить его с помощью rustc main.rs &&./main.


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL rust(("Rust")) -.-> rust/BasicConceptsGroup(["Basic Concepts"]) rust(("Rust")) -.-> rust/DataTypesGroup(["Data Types"]) rust(("Rust")) -.-> rust/FunctionsandClosuresGroup(["Functions and Closures"]) rust(("Rust")) -.-> rust/AdvancedTopicsGroup(["Advanced Topics"]) rust(("Rust")) -.-> rust/MemorySafetyandManagementGroup(["Memory Safety and Management"]) rust/BasicConceptsGroup -.-> rust/variable_declarations("Variable Declarations") rust/DataTypesGroup -.-> rust/integer_types("Integer Types") rust/DataTypesGroup -.-> rust/floating_types("Floating-point Types") rust/DataTypesGroup -.-> rust/type_casting("Type Conversion and Casting") rust/FunctionsandClosuresGroup -.-> rust/function_syntax("Function Syntax") rust/FunctionsandClosuresGroup -.-> rust/expressions_statements("Expressions and Statements") rust/MemorySafetyandManagementGroup -.-> rust/lifetime_specifiers("Lifetime Specifiers") rust/AdvancedTopicsGroup -.-> rust/unsafe_rust("Unsafe Rust") rust/AdvancedTopicsGroup -.-> rust/operator_overloading("Traits for Operator Overloading") subgraph Lab Skills rust/variable_declarations -.-> lab-99295{{"Приведение типов в Rust: явное преобразование типов"}} rust/integer_types -.-> lab-99295{{"Приведение типов в Rust: явное преобразование типов"}} rust/floating_types -.-> lab-99295{{"Приведение типов в Rust: явное преобразование типов"}} rust/type_casting -.-> lab-99295{{"Приведение типов в Rust: явное преобразование типов"}} rust/function_syntax -.-> lab-99295{{"Приведение типов в Rust: явное преобразование типов"}} rust/expressions_statements -.-> lab-99295{{"Приведение типов в Rust: явное преобразование типов"}} rust/lifetime_specifiers -.-> lab-99295{{"Приведение типов в Rust: явное преобразование типов"}} rust/unsafe_rust -.-> lab-99295{{"Приведение типов в Rust: явное преобразование типов"}} rust/operator_overloading -.-> lab-99295{{"Приведение типов в Rust: явное преобразование типов"}} end

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

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

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

// Suppress all warnings from casts which overflow.
#![allow(overflowing_literals)]

fn main() {
    let decimal = 65.4321_f32;

    // Ошибка! Нет неявного преобразования
    let integer: u8 = decimal;
    // FIXME ^ Comment out this line

    // Явное преобразование
    let integer = decimal as u8;
    let character = integer as char;

    // Ошибка! В правилах преобразования есть ограничения.
    // Число с плавающей точкой не может быть напрямую преобразовано в char.
    let character = decimal as char;
    // FIXME ^ Comment out this line

    println!("Приведение типов: {} -> {} -> {}", decimal, integer, character);

    // При приведении любого значения к беззнаковому типу, T,
    // к значению прибавляется или вычитается T::MAX + 1, пока оно
    // не войдёт в новый тип

    // 1000 уже помещается в u16
    println!("1000 в виде u16 равно: {}", 1000 as u16);

    // 1000 - 256 - 256 - 256 = 232
    // Внутри происходит сокращение старших битов, начиная с 8-го младшего бита (LSB),
    // а остальные биты до старших (MSB) обрезаются.
    println!("1000 в виде u8 равно : {}", 1000 as u8);
    // -1 + 256 = 255
    println!("  -1 в виде u8 равно : {}", (-1i8) as u8);

    // Для положительных чисел это то же самое, что и остаток от деления
    println!("1000 mod 256 равно : {}", 1000 % 256);

    // При приведении к знаковому типу результат (битовое) такой же,
    // как при приведении к соответствующему беззнаковому типу. Если самый
    // старший бит этого значения равен 1, то значение отрицательное.

    // Если оно уже помещается, конечно, исключения нет.
    println!(" 128 в виде i16 равно: {}", 128 as i16);

    // В граничном случае значение 128 в 8-разрядной двоичной системе с дополнительным кодом равно -128
    println!(" 128 в виде i8 равно : {}", 128 as i8);

    // Повторение примера выше
    // 1000 в виде u8 -> 232
    println!("1000 в виде u8 равно : {}", 1000 as u8);
    // а значение 232 в 8-разрядной двоичной системе с дополнительным кодом равно -24
    println!(" 232 в виде i8 равно : {}", 232 as i8);

    // С версии Rust 1.45 ключевое слово `as` выполняет *saturating cast*
    // при приведении от числа с плавающей точкой к целому типу. Если значение
    // с плавающей точкой выходит за верхнюю границу или меньше нижней границы,
    // возвращаемое значение будет равно границе, которую оно пересекло.

    // 300.0 в виде u8 равно 255
    println!(" 300.0 в виде u8 равно : {}", 300.0_f32 as u8);
    // -100.0 в виде u8 равно 0
    println!("-100.0 в виде u8 равно : {}", -100.0_f32 as u8);
    // nan в виде u8 равно 0
    println!("   nan в виде u8 равно : {}", f32::NAN as u8);

    // Это поведение имеет небольшую стоимость времени выполнения и его можно
    // избежать с использованием небезопасных методов, однако результаты могут
    // быть переполнеными и возвращать **несовершенные значения**. Используйте
    // эти методы с умом:
    unsafe {
        // 300.0 в виде u8 равно 44
        println!(" 300.0 в виде u8 равно : {}", 300.0_f32.to_int_unchecked::<u8>());
        // -100.0 в виде u8 равно 156
        println!("-100.0 в виде u8 равно : {}", (-100.0_f32).to_int_unchecked::<u8>());
        // nan в виде u8 равно 0
        println!("   nan в виде u8 равно : {}", f32::NAN.to_int_unchecked::<u8>());
    }
}

Резюме

Поздравляем! Вы завершили лабу по приведению типов. Вы можете практиковаться в других лабах в LabEx, чтобы улучшить свои навыки.