Не столь тривиальные приведения типов

От Nikita Bishonen1 minute read



Не столь тривиальные приведения типов

В Rust существует интересный lint под названием trivial_casts, который оказывается не таким уж тривиальным.

It may be possible that this will become a warning in the future

поэтому давайте рассмотрим несколько примеров кода, где я буду сравнивать:

  1. Тривиальные приведения типов
  2. Определения типов переменных
  3. Неявное приведение типа

Я не буду добавлять никаких комментариев, кроме вывода компилятора, чтобы вы могли увидеть разницу самостоятельно и решить, когда и как использовать приведение типов в коде Rust. Я только скажу, что trivial_cast_supertype_with_shadowing похоже является хорошим примером того, как trivial_casts могут стать не столь тривиальными даже в небольшом примере (представьте, что может произойти в более длинной цепочке вызовов и преобразований/приведений типов).

#![allow(dead_code)]
#![warn(trivial_casts)]

trait Polygon {}
trait TwoSidedPolygon: Polygon {}

struct Square([u32; 8]);
impl Polygon for Square {}
impl TwoSidedPolygon for Square {}

struct Triangle([u32; 6]);
impl Polygon for Triangle {}

#[cfg(test)]
mod tests {
    use crate::{Polygon, Square, Triangle, TwoSidedPolygon};

    #[test]
    fn explicit_definition_supertype() {
        let square = Square([2; 8]);
        let square: &dyn Polygon = □
        process(square);
        // process2(square); the size for values of type `dyn Polygon` cannot be known at compilation time
        // process3(square); the trait bound `dyn Polygon: TwoSidedPolygon` is not satisfied
        // process_square(square); expected &Square, found &(dyn Polygon + 'static)
    }

    #[test]
    fn explicit_definition_subtype() {
        let square = Square([2; 8]);
        let square: &dyn TwoSidedPolygon = □
        process(square);
        // process2(square); the size for values of type `dyn Polygon` cannot be known at compilation time
        process3(square);
        // process_square(square); expected &Square, found &(dyn TwoSidedPolygon + 'static)
    }

    #[test]
    fn trivial_cast_supertype() {
        let square = Square([2; 8]);
        let square = &square as &dyn Polygon; // trivial cast: `&Square` as `&dyn Polygon`
        process(square);
        // process2(square); the size for values of type `dyn Polygon` cannot be known at compilation time
        // process3(square); the trait bound `dyn Polygon: TwoSidedPolygon` is not satisfied
        // process_square(square); expected &Square, found &dyn Polygon
    }

    #[test]
    fn trivial_cast_subtype() {
        let square = Square([2; 8]);
        let square = &square as &dyn TwoSidedPolygon; // trivial cast: `&Square` as `&dyn TwoSidedPolygon` 
        process(square);
        // process2(square); the size for values of type `dyn Polygon` cannot be known at compilation time
        process3(square);
        // process_square(square); expected &Square, found &(dyn TwoSidedPolygon + 'static)
    }

    #[test]
    fn trivial_cast_struct_type() {
        let square = Square([2; 8]);
        let square = &square as □ // trivial cast: `&Square` as `&Square`
        process(square);
        process2(square);
        process3(square);
        process_square(square);
    }

    #[test]
    fn auto_coercion() {
        let square = Square([2; 8]);
        let polygon = □
        process(polygon);
        process2(polygon);
        process3(polygon);
        process_square(polygon);
    }

    #[test]
    fn shadowed_auto_coercion() {
        let square = Square([2; 8]);
        let square = Triangle([3; 6]);
        let square = □
        process(square);
        process2(square);
        // process3(square); the trait bound `Triangle: TwoSidedPolygon` is not satisfied
        // process_square(square); expected &Square, found &Triangle
        process_triangle(square);
    }

    #[test]
    fn trivial_cast_supertype_with_shadowing() {
        let square = Square([2; 8]);
        let square = Triangle([3; 6]);
        let square = &square as &dyn Polygon; // trivial cast: `&Square` as `&Square`
        process(square);
        // process2(square); the size for values of type `dyn Polygon` cannot be known at compilation time
        // process3(square); the trait bound `dyn Polygon: TwoSidedPolygon` is not satisfied
        // process_square(square);  expected &Square, found &dyn Polygon
    }

    fn process_square(_square: &Square) {}
    fn process_triangle(_triangle: &Triangle) {}
    fn process(_polygon: &(impl Polygon + ?Sized)) {}
    fn process2(_polygon: &impl Polygon) {}
    fn process3(_polygon: &(impl TwoSidedPolygon + ?Sized)) {}
}

Комментарии

Вы можете оставить комментарий к этому блог-посту, публично ответив на него с помощью аккаунта Mastodon или другого аккаунта ActivityPub/Fediverse. Известные неприватные ответы отображены ниже.

Открыть Пост