转换 [[T; 的最佳方法是什么? 4]; 3] 变成 [T; 12]?
What's the best way to convert a [[T; 4]; 3] into a [T; 12]?
据我了解,[[T; 4]; 3]
和 [T; 12]
在内存中具有相同的布局。在这些类型之间转换值的最佳方法是什么?我可以将对一个的引用转换为对另一个的引用吗?我可以避免复制所有元素吗?我需要 unsafe
吗?
免责声明:我对 Rust 的低级方面还不是很了解,我不知道在低级 Rust 中什么被认为是 "good practice"。这里给出的建议可能不是好主意。不过我把它们放在这里是因为......好吧,它们有效。
You could transmute them。问题是它将是一个副本,文档说它等同于 memcpy
调用。这不是您想要的,但无论如何:
fn main() {
let a: [[u8; 4]; 3] = [[1, 2, 3, 4], [1, 2, 3, 4], [1, 2, 3, 4]];
let b: [u8; 12] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
println!("a: {:?}", a);
println!("b: {:?}", b);
let c = unsafe { std::mem::transmute::<[[u8; 4]; 3], [u8; 12]>(a) };
println!("c: {:?}", c);
}
你的另一个选择is to work with a raw pointer:
fn main() {
let a: [[u8; 4]; 3] = [[1, 2, 3, 4], [1, 2, 3, 4], [1, 2, 3, 4]];
let b: [u8; 12] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
println!("a: {:?}", a);
println!("b: {:?}", b);
let c = &a as *const _ as *const [u8; 12];
// Or it can be this: let c = &mut a as *mut [[u8; 4]; 3];
for i in 0..12 {
let p = c as *const u8;
let v = unsafe { *p.offset(i) };
println!("{}", v);
}
}
也不是特别好。
指针也可以是指向相同类型的指针或可变指针(因为&mut T
可以转换为*mut T
),上面的代码工作完全相同(与a
标记为可变):
let c = &mut a as *mut [[u8; 4]; 3];
我想知道这是否有点 XY 问题。也许您处理数据的方式可以更改为不需要这个?
是的,您可以将对 [[T; 4]; 3]
的引用转换为对 [T; 12]
的引用,但只能使用不安全代码,使用 mem::transmute
。最好将其包装在一个函数中,以便为生成的引用分配适当的生命周期,否则 transmute
可以获得比引用应有的生命周期更长的引用。
fn convert<'a>(a: &'a [[u8; 4]; 3]) -> &'a [u8; 12] {
unsafe { std::mem::transmute(a) }
}
由于生命周期省略规则,这可以缩短:
fn convert(a: &[[u8; 4]; 3]) -> &[u8; 12] {
unsafe { std::mem::transmute(a) }
}
虽然在处理不安全代码时,如果您更喜欢更明确的版本,我会理解!
据我了解,[[T; 4]; 3]
和 [T; 12]
在内存中具有相同的布局。在这些类型之间转换值的最佳方法是什么?我可以将对一个的引用转换为对另一个的引用吗?我可以避免复制所有元素吗?我需要 unsafe
吗?
免责声明:我对 Rust 的低级方面还不是很了解,我不知道在低级 Rust 中什么被认为是 "good practice"。这里给出的建议可能不是好主意。不过我把它们放在这里是因为......好吧,它们有效。
You could transmute them。问题是它将是一个副本,文档说它等同于 memcpy
调用。这不是您想要的,但无论如何:
fn main() {
let a: [[u8; 4]; 3] = [[1, 2, 3, 4], [1, 2, 3, 4], [1, 2, 3, 4]];
let b: [u8; 12] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
println!("a: {:?}", a);
println!("b: {:?}", b);
let c = unsafe { std::mem::transmute::<[[u8; 4]; 3], [u8; 12]>(a) };
println!("c: {:?}", c);
}
你的另一个选择is to work with a raw pointer:
fn main() {
let a: [[u8; 4]; 3] = [[1, 2, 3, 4], [1, 2, 3, 4], [1, 2, 3, 4]];
let b: [u8; 12] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
println!("a: {:?}", a);
println!("b: {:?}", b);
let c = &a as *const _ as *const [u8; 12];
// Or it can be this: let c = &mut a as *mut [[u8; 4]; 3];
for i in 0..12 {
let p = c as *const u8;
let v = unsafe { *p.offset(i) };
println!("{}", v);
}
}
也不是特别好。
指针也可以是指向相同类型的指针或可变指针(因为&mut T
可以转换为*mut T
),上面的代码工作完全相同(与a
标记为可变):
let c = &mut a as *mut [[u8; 4]; 3];
我想知道这是否有点 XY 问题。也许您处理数据的方式可以更改为不需要这个?
是的,您可以将对 [[T; 4]; 3]
的引用转换为对 [T; 12]
的引用,但只能使用不安全代码,使用 mem::transmute
。最好将其包装在一个函数中,以便为生成的引用分配适当的生命周期,否则 transmute
可以获得比引用应有的生命周期更长的引用。
fn convert<'a>(a: &'a [[u8; 4]; 3]) -> &'a [u8; 12] {
unsafe { std::mem::transmute(a) }
}
由于生命周期省略规则,这可以缩短:
fn convert(a: &[[u8; 4]; 3]) -> &[u8; 12] {
unsafe { std::mem::transmute(a) }
}
虽然在处理不安全代码时,如果您更喜欢更明确的版本,我会理解!