How do I convert a Vec<T> to a Vec<U> without copying the vector?

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 or the same 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.


The best thing to do is to create a new vector:

let buffer2 = buffer.into_iter().map(Foo).collect();

You could also adjust do_something_using_foo to take in a common generic type that both Foo and u32 implement:

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);
}

In unsafe Rust, it is 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:

  • Using map with Vectors
  • Converting a Vec<u32> to Vec<u8> in-place and with minimal overhead

According to the documentation of std::mem::transmute(), using Vec::from_raw_parts combined with ManuallyDrop is the best option, as of Rust 1.38:

let v_from_raw = unsafe {
    // Ensure the original vector is not dropped.
    let mut v_clone = std::mem::ManuallyDrop::new(v_orig);
    Vec::from_raw_parts(v_clone.as_mut_ptr() as *mut U,
                        v_clone.len(),
                        v_clone.capacity())
};

The prerequisite for this is that T and U have the same size, the same minimum alignment and that all bit patterns that are valid for T are also valid for U. If you define T and U as in your question, you don't have a guarantee for this.

struct U(T) defines a tuple struct, and the memory layout of such a struct is completely undefined. However, it is possible to force the memory representations to be identical by using the transparent representation:

#[repr(transparent)]
struct U(T);

Future possibilities

Nightly Rust has Vec::into_raw_parts, which reduces the amount of code and places to go wrong:

#![feature(vec_into_raw_parts)]

fn convert_using_into_raw_parts(v: Vec<T>) -> Vec<U> {
    let (ptr, len, cap) = v.into_raw_parts();
    unsafe { Vec::from_raw_parts(ptr as *mut U, len, cap) }
}

There's also an open RFC Collection Transmute #2756 which proposes adding a Vec::transmute method.

Tags:

Rust