You cannot change the type of a value in place in safe Rust. There is no guarantee that the two types will have the same size, alignment, or semantics.
This applies to a single value (T
-> U
) as well as aggregate values (Vec<T>
-> Vec<U>
, HashMap<K1, V1>
-> HashMap<K2, V2>
). Note that aggregate values are really just a special case of “single” values.
Create a new vector
The most straight-forward solution:
let buffer2 = buffer.into_iter().map(Foo).collect();
In cases where the compiler can tell that you aren’t actually changing important things, this becomes effectively a no-op:
fn convert(b: Vec<u32>) -> Vec<Foo> {
b.into_iter().map(Foo).collect()
}
x86_64 assembly output for Rust 1.54 with optimizations:
playground::convert:
movq %rdi, %rax
movq (%rsi), %rcx
movups 8(%rsi), %xmm0
movq %rcx, (%rdi)
movups %xmm0, 8(%rdi)
retq
Unfortunately, this lightweight transformation isn’t currently a guaranteed property, only an implementation detail.
Use generics
You could adjust do_something_using_foo
to take in a generic type and have both Foo
and u32
implement a trait:
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);
}
Unsafe Rust
It’s technically possible — you can shoot yourself in the foot as much as you’d like.
You can use something like std::mem::transmute
if you know what you are doing.
However, it’s undefined behavior to use transmute
with Vec
as the representation of Vec
is not defined. Instead, see Sven Marnach’s answer.
See also: