在 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 怎么办?)
出于显而易见的原因,这需要
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。
除了@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 }]
}