我想将Vec<T>
转换为Vec<U>
,其中T
是某种原始类型,U
是T
的新类型:struct U(T)
。
我试过这样的事情:
struct Foo(u32);
fn do_something_using_foo(buffer: &mut Vec<Foo>) {}
fn main() {
let buffer: Vec<u32> = vec![0; 100];
do_something_using_foo(&mut buffer as Vec<Foo>);
}
我不想复制矢量,我想在新类型u32
中包装Foo
字段。
这给出了错误:
error[E0308]: mismatched types
--> main.rs:8:28
|
8 | do_something_using_foo(&mut buffer as Vec<Foo>);
| ^^^^^^^^^^^^^^^^^^^^^^^ expected mutable reference, found struct `std::vec::Vec`
|
= note: expected type `&mut std::vec::Vec<Foo>`
found type `std::vec::Vec<Foo>`
= help: try with `&mut &mut buffer as Vec<Foo>`
error: non-scalar cast: `&mut std::vec::Vec<u32>` as `std::vec::Vec<Foo>`
--> main.rs:8:28
|
8 | do_something_using_foo(&mut buffer as Vec<Foo>);
| ^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error(s)
您无法在安全Rust中更改值的类型。无法保证这两种类型具有相同的大小或相同的语义。
这适用于单个值(T
- > U
)以及聚合值(Vec<T>
- > Vec<U>
,HashMap<K1, V1>
- > HashMap<K2, V2>
)。请注意,聚合值实际上只是“单个”值的特例。
最好的办法是创建一个新的向量:
let buffer2 = buffer.into_iter().map(Foo).collect();
您还可以调整do_something_using_foo
以采用Foo
和u32
实现的通用泛型类型:
use std::borrow::{Borrow, BorrowMut};
#[derive(Debug, Clone)]
struct Foo(u32);
impl Borrow<u32> for Foo {
fn borrow(&self) -> &u32 {
&self.0
}
}
impl BorrowMut<u32> for Foo {
fn borrow_mut(&mut self) -> &mut u32 {
&mut self.0
}
}
fn do_something_using_foo<T>(buffer: &mut [T])
where
T: BorrowMut<u32>,
{
}
fn main() {
let mut buffer_u32 = vec![0u32; 100];
let mut buffer_foo = vec![Foo(0); 100];
do_something_using_foo(&mut buffer_u32);
do_something_using_foo(&mut buffer_foo);
}
在不安全的Rust中,技术上是可行的 - 你可以根据自己的喜好自己射击脚。
如果你知道你在做什么,你可以使用像std::mem::transmute
这样的东西。
对于Vec
,我首先看看已弃用和删除的函数Vec::map_in_place
。请注意,它是一个170行的功能,充满了不安全的代码和图表,争论为什么它实际上是安全的。它已从标准库中删除,因为没有人想要维护它。
也可以看看:
根据documentation of std::mem::transmute()
,您可以执行以下操作来进行Vec
的就地转换:
let v_new = unsafe {
Vec::from_raw_parts(v_orig.as_mut_ptr() as *mut U,
v_orig.len(),
v_orig.capacity())
};
std::mem::forget(v_orig);
前提条件是T
和U
具有相同的大小,相同的最小对齐,并且对T
有效的所有位模式对U
也有效。如果您在问题中定义T
和U
,则无法保证这一点。
struct U(T)
定义了一个元组结构,这种结构的内存布局是完全未定义的。但是,可以使用the transparent
representation强制内存表示相同:
#[repr(transparent)]
struct U(T);