将相同叶类型的嵌套结构视为数组

问题描述 投票:0回答:2

在 C 中,我可以像

struct
一样在这里取一个
figure

struct point
{
    int x, y;
};

struct box
{
    struct point left_top, right_bottom;
};

struct figure
{
    struct point points[100];
    struct box bounding_box;
};

并且只是把它当作一个

int
数组,在某些情况下这很方便。我想知道 Rust 是否提供任何类似的设施?如果不是直接把一个嵌套的
struct
当作一个数组,那么只是为了迭代? (例如,如果我想将所有
ints
递增 1 怎么办?)

rust
2个回答
2
投票

出于显而易见的原因,这需要

unsafe
但确保可以做到:

#[repr(C)]
#[derive(Debug)]
struct Point {
    x: usize,
    y: usize,
}

#[repr(C)]
#[derive(Debug)]
struct Box {
    left_top: Point,
    right_bottom: Point,
}

#[repr(C)]
#[derive(Debug)]
struct Figure {
    points: [Point; 5],
    bounding_box: Box,
}

fn main() {
    let mut f = Figure {
        points: [
            Point { x: 1, y: 2 },
            Point { x: 3, y: 4 },
            Point { x: 5, y: 6 },
            Point { x: 7, y: 8 },
            Point { x: 9, y: 10 },
        ],
        bounding_box: Box {
            left_top: Point { x: 11, y: 12 },
            right_bottom: Point { x: 13, y: 14 }
        },
    };

    assert_eq!(std::mem::size_of::<[usize;14]>(), std::mem::size_of::<Figure>());

    let g: &mut [usize; 14] = unsafe { &mut *(&mut f as *mut Figure).cast() };
    for l in g {
        *l += 1;
    }

    dbg!(f);
}

当然,通常你会想把它隐藏在一个安全的抽象背后,比如

AsRef
AsMut
:

impl AsRef<[usize; 14]> for Figure {
    fn as_ref(&self) -> &[usize; 14] {
        assert_eq!(std::mem::size_of::<[usize;14]>(), std::mem::size_of::<Figure>());
        unsafe { &*(self as *const Figure).cast() }
    }
}

impl AsMut<[usize; 14]> for Figure {
    fn as_mut(&mut self) -> &mut [usize; 14] {
        assert_eq!(std::mem::size_of::<[usize;14]>(), std::mem::size_of::<Figure>());
        unsafe { &mut *(self as *mut Figure).cast() }
    }
}

请注意,如果没有

#[repr(C)]
,编译器可以随意安排字段(顺序、填充),因此这段代码将是 UB。


0
投票

除了@cafce25的不安全解决方案,你还可以在完全安全的代码中进行迭代:

#[derive(Debug)]
struct Point {
    x: i32,
    y: i32,
}

fn pts_ints_mut(pts: &mut [Point]) -> impl '_ + Iterator<Item = &mut i32> {
    pts.iter_mut()
        .flat_map(|pt| [&mut pt.x, &mut pt.y])
        //             ^^^^^^^^^^^^^^^^^^^^^^
        //             must specify all ints in `Point`

}


fn main() {
    let mut pts = [
        Point { x: 1, y: 2 },
        Point { x: 3, y: 4 },
    ];
    
    println!("{pts:?}"); // [Point { x: 1, y: 2 }, Point { x: 3, y: 4 }]
    
    // get iterator of mutable references to each integer
    pts_ints_mut(&mut pts)
        // do something with that iterator
        .for_each(|n| *n += 1);
        
    println!("{pts:?}"); // [Point { x: 2, y: 3 }, Point { x: 4, y: 5 }]
}
© www.soinside.com 2019 - 2024. All rights reserved.