On stable, that's about as good as it gets at the moment.
There are a couple of nightly-only features that make working with uninitialized memory more ergonomic and less unsafe.
#![feature(vec_spare_capacity)]
#![feature(maybe_uninit_extra)]
fn make_vec() -> Vec<u8> {
let mut buf = Vec::with_capacity(1024);
let data = buf.spare_capacity_mut();
for idx in 0..1024 {
data[idx].write((idx * idx) as u8); // no `unsafe` here
}
unsafe {
buf.set_len(1024);
}
buf
}
Yup, see the example in its docs of using FFI to write into the buffer then set_len to the initialized length: std::vec::Vec - Rust
There may also be other ways, but we'd need more information to help with that. (I assume the actual population code you put there is a placeholder, since there's an easy just-as-fast same-one-allocation safe version of it.)
Let me step back and ask: is this something you really need, i.e. have you benchmarked that it has a measurable or meaningful impact on the performance of your code? You could as well zero-initialize the array using vec![0; 1024], because modern OSes almost universally provide pre-zeroed memory, which Rust allocators can also use with no performance penalty and without actually performing a bunch of byte-wise dead writes.