How to allocate space for a Vec<T> in Rust? - vector

I want to create a Vec<T> and make some room for it, but I don't know how to do it, and, to my surprise, there is almost nothing in the official documentation about this basic type.
let mut v: Vec<i32> = Vec<i32>(SIZE); // How do I do this ?
for i in 0..SIZE {
v[i] = i;
}
I know I can create an empty Vec<T> and fill it with pushes, but I don't want to do that since I don't always know, when writing a value at index i, if a value was already inserted there yet. I don't want to write, for obvious performance reasons, something like :
if i >= len(v) {
v.push(x);
} else {
v[i] = x;
}
And, of course, I can't use the vec! syntax either.

While vec![elem; count] from the accepted answer is sufficient to create a vector with all elements equal to the same value, there are other convenience functions.
Vec::with_capacity() creates a vector with the given capacity but with zero length. It means that until this capacity is reached, push() calls won't reallocate the vector, making push() essentially free:
fn main() {
let mut v = Vec::with_capacity(10);
for i in 0..10 {
v.push(i);
}
println!("{:?}", v);
}
You can also easily collect() a vector from an iterator. Example:
fn main() {
let v: Vec<_> = (1..10).collect();
println!("{:?}", v);
}
And finally, sometimes your vector contains values of primitive type and is supposed to be used as a buffer (e.g. in network communication). In this case you can use Vec::with_capacity() + set_len() unsafe method:
fn main() {
let mut v = Vec::with_capacity(10);
unsafe { v.set_len(10); }
for i in 0..10 {
v[i] = i;
}
println!("{:?}", v);
}
Note that you have to be extra careful if your vector contains values with destructors or references - it's easy to get a destructor run over a uninitialized piece of memory or to get an invalid reference this way. It will also work right if you only use initialized part of the vector (you have to track it yourself now). To read about all the possible dangers of uninitialized memory, you can read the documentation of mem::uninitialized().

You can use the first syntax of the vec! macro, specifically vec![elem; count]. For example:
vec![1; 10]
will create a Vec<_> containing 10 1s (the type _ will be determined later or default to i32). The elem given to the macro must implement Clone. The count can be a variable, too.

There is the Vec::resize method:
fn resize(&mut self, new_len: usize, value: T)
This code resizes an empty vector to 1024 elements by filling with the value 7:
let mut vec: Vec<i32> = Vec::new();
vec.resize(1024, 7);

Related

How to traverse character elements of *const char pointer in Rust?

I'm new to Rust programing and I have a bit of difficulty when this language is different from C Example, I have a C function as follows:
bool check(char* data, int size){
int i;
for(i = 0; i < size; i++){
if( data[i] != 0x00){
return false;
}
}
return true;
}
How can I convert this function to Rust? I tried it like C, but it has Errors :((
First off, I assume that you want to use as little unsafe code as possible. Otherwise there really isn't any reason to use Rust in the first place, as you forfeit all the advantages it brings you.
Depending on what data represents, there are multiple ways to transfer this to Rust.
First off: Using pointer and length as two separate arguments is not possible in Rust without unsafe. It has the same concept, though; it's called slices. A slice is exactly the same as a pointer-size combination, just that the compiler understands it and checks it for correctness at compile time.
That said, a char* in C could actually be one of four things. Each of those things map to different types in Rust:
Binary data whose deallocation is taken care of somewhere else (in Rust terms: borrowed data)
maps to &[u8], a slice. The actual content of the slice is:
the address of the data as *u8 (hidden from the user)
the length of the data as usize
Binary data that has to be deallocated within this function after using it (in Rust terms: owned data)
maps to Vec<u8>; as soon as it goes out of scope the data is deleted
actual content is:
the address of the data as *u8 (hidden from the user)
the length of the data as usize
the size of the allocation as usize. This allows for efficient push()/pop() operations. It is guaranteed that the length of the data does not exceed the size of the allocation.
A string whose deallocation is taken care of somewhere else (in Rust terms: a borrowed string)
maps to &str, a so called string slice.
This is identical to &[u8] with the additional compile time guarantee that it contains valid UTF-8 data.
A string that has to be deallocated within this function after using it (in Rust terms: an owned string)
maps to String
same as Vec<u8> with the additional compile time guarantee that it contains valid UTF-8 data.
You can create &[u8] references from Vec<u8>'s and &str references from Strings.
Now this is the point where I have to make an assumption. Because the function that you posted checks if all of the elements of data are zero, and returns false if if finds a non-zero element, I assume the content of data is binary data. And because your function does not contain a free call, I assume it is borrowed data.
With that knowledge, this is how the given function would translate to Rust:
fn check(data: &[u8]) -> bool {
for d in data {
if *d != 0x00 {
return false;
}
}
true
}
fn main() {
let x = vec![0, 0, 0];
println!("Check {:?}: {}", x, check(&x));
let y = vec![0, 1, 0];
println!("Check {:?}: {}", y, check(&y));
}
Check [0, 0, 0]: true
Check [0, 1, 0]: false
This is quite a direct translation; it's not really idiomatic to use for loops a lot in Rust. Good Rust code is mostly iterator based; iterators are most of the time zero-cost abstraction that can get compiled very efficiently.
This is how your code would look like if rewritten based on iterators:
fn check(data: &[u8]) -> bool {
data.iter().all(|el| *el == 0x00)
}
fn main() {
let x = vec![0, 0, 0];
println!("Check {:?}: {}", x, check(&x));
let y = vec![0, 1, 0];
println!("Check {:?}: {}", y, check(&y));
}
Check [0, 0, 0]: true
Check [0, 1, 0]: false
The reason this is more idiomatic is that it's a lot easier to read for someone who hasn't written it. It clearly says "return true if all elements are equal to zero". The for based code needs a second to think about to understand if its "all elements are zero", "any element is zero", "all elements are non-zero" or "any element is non-zero".
Note that both versions compile to the exact same bytecode.
Also note that, unlike the C version, the Rust borrow checker guarantees at compile time that data is valid. It's impossible in Rust (without unsafe) to produce a double free, a use-after-free, an out-of-bounds array access or any other kind of undefined behaviour that would cause memory corruption.
This is also the reason why Rust doesn't do pointers without unsafe - it needs the length of the data to check out-of-bounds errors at runtime. That means, accessing data via [] operator is a little more costly in Rust (as it does perform an out-of-bounds check every time), which is the reason why iterator based programming is a thing. Iterators can iterate over data a lot more efficient than directly accessing it via [] operators.

How to properly initialize a vector in Rust, given that the vector will be immutable after the initialization?

What is a good way to initialize the vector, without the mut keyword, given that the vector will be immutable after the initialization?
For example:
// nums is a `i32` vector(Vec<i32>)
// here is to pad two 1s with both ends
let mut padded: Vec<i32> = vec![0; len_p];
padded[0] = 1;
padded[len_n + 1] = 1;
for (idx, &num) in nums.iter().enumerate(){
padded[idx + 1] = num;
}
// `padded` will be read-only/immutable ever since
Otherwise, to mark padded mut, simply to initialize it, seems to me a waste of immutability, since I cannot enforce it after the initialization.
A common idiom seen in Rust is to introduce a local scope for just this purpose.
let padded: Vec<i32> = {
let mut tmp: Vec<i32> = vec![0; len_p];
tmp[0] = 1;
tmp[len_n + 1] = 1;
for (idx, &num) in nums.iter().enumerate(){
tmp[idx + 1] = num;
}
tmp
};
Inside the nested scope, we have a local variable called tmp which is mutable. Then, when we get to the end of that scope, we pass ownership of that vector to the immutable variable padded. The compiler is free to (and likely will) optimize out any actual movement that's happening, and this will compile to something as efficient as what you wrote. But from the borrow checker's perspective, tmp is mutable and padded is immutable, as desired. Once tmp goes out of scope, there's no way to modify padded anymore.
Remember, the owner of a value always determines whether or not that value is mutable, so when you pass ownership to someone else, they're free to change the mutability of the value upon taking ownership.
There are 3 ways:
Most functional (FP) approach: Use collect
let v: Vec<i32> = std::iter::once(1).chain(
nums.iter().copied()
)
.collect();
Initialize in scope. Useful when you need some extra variables which would be cleaned up after this.
let v = {
let mut v: Vec<i32> = vec![0; len_p];
v[0] = 1;
v[len_n + 1] = 1;
for (&src, dst) in nums.iter().zip(v[1..].iter_mut()){
*dst = src;
}
v
}
Rebind name and move vector into it. Useful when initialization is clear and simple.
let mut v: Vec<i32> = vec![0; len_p];
v[0] = 1;
v[len_n + 1] = 1;
for (&src, dst) in nums.iter().zip(v[1..].iter_mut()){
*dst = src;
}
// Rebind to immutable variable
let v = v;
// Cannot mutate here

Getting pointer by &str

Consider this pseudocode:
let k = 10;
let ptr = &k as *const k;
println!("{:p}", ptr); // prints address of pointer
let addr = format!("{:p}", ptr);
super-unsafe {
// this would obviously be super unsafe. It may even cause a STATUS_ACCESS_VIOLATION if you try getting memory from a page that the OS didn't allocate to the program!
let ptr_gen = PointerFactory::from_str(addr.as_str());
assert_eq!(k, *ptr_gen);
}
The pseudocode gets the idea across: I want to be able to get a pointer to a certain memory address by its &str representation. Is this... possible?
So essentially what you want to do is parse the string back to an integer (usize) and then interpret that value as a pointer/reference†:
fn main()
{
let i = 12i32;
let r = format!("{:p}", &i);
let x = unsafe
{
let r = r.trim_start_matches("0x");
&*(usize::from_str_radix(&r, 16).unwrap() as *const i32)
};
println!("{}", x);
}
You can try this yourself in the playground.
†As you can see, you don't even need to cast your reference into a raw pointer, the {:p} formatter takes care of representing it as a memory location (index).
Update: As E_net4 mentioned this in the comment section, it is better to use usize here, which is architecture defined unlike the machine sized one. The transmute was not necessary, so I removed it. The third point about undefined behaviour however seems obvious to whomever tries to do something like the above. This answer provides a way to achieve what the OP asked for which doesn't mean this should be used for anything else than academic/experimental purposes :)

If I want to code in Rust securely, should I code without using pointer arithmetic?

I've read that pointer arithmetic in Rust can be done through the pointer.offset() function, but it always has to be implemented in unsafe code:
fn main() {
let buf: [u32; 5] = [1, 2, 3, 4, 5];
let mut ptr1: *const u32 = buf.as_ptr();
unsafe {
let ptr2: *const u32 = buf.as_ptr().offset(buf.len() as isize);
while ptr1 < ptr2 {
println!("Address {:?} | Value {}", ptr1, *ptr1);
ptr1 = ptr1.offset(1);
}
}
}
If I want to code in Rust securely, should I code without using pointer arithmetic and just using the corresponding index of an array for example? Or is there any other way?
If I want to code in Rust securely
Then you should not use unsafe. There are a few legit reasons for unsafe (e.g. accessing memory locations that are known and safe to use, e.g. on microcontrollers several registers), but generally you should not use it.
should I code without using pointer arithmetic and just using the corresponding index of an array for example
Yes. There is no reason (in this specific case) to use unsafe at all. Just use
for i in 0..buf.len() {
println!("Value {}", buf[i]);
}
This code however is not considered as "rusty", instead use a for-loop
for i in &buf {
println!("Value {}", i);
}
Using raw pointers like that is very unlikely[1] to be faster than an idiomatic for loop over an iterator:
fn main() {
let buf: [u32; 5] = [1, 2, 3, 4, 5];
for val in buf.iter() {
println!("Address {:?} | Value {}", val as *const u32, val);
}
}
This is also much easier to read and doesn't introduce memory unsafety risks.
1 In fact, your code compares two pointer values each iteration, so is likely to be much slower than the idiomatic for loop, which can often omit all bounds checks.

How can I change the length of a vector in Rust?

Editor's note: This question predates Rust 1.0 and syntax and methods have changed since then. Some answers account for Rust 1.0.
I have a function which I would like to have modify a vector in place.
fn f(v: &mut Vec<int>) {
v = Vec::from_elem(10 as uint, 0i);
}
fn main() {
let mut v: Vec<int> = Vec::new();
f(&mut v);
}
But this fails to compile. Specifically, I would like to resize v to contain 10 elements of value zero. What am I doing wrong?
Use the clear and resize methods. (This seems to be the right answer as of Rust 1.0 and 1.5, respectively.)
fn f(v: &mut Vec<u32>) {
// Remove all values in the vector
v.clear();
// Fill the vector with 10 zeros
v.resize(10, 0);
}
fn main() {
let mut v: Vec<u32> = Vec::new();
f(&mut v);
assert!(v == [0,0,0,0,0,0,0,0,0,0]);
}
Editor's note: This answer predates Rust 1.0 and is no longer necessarily accurate. Other answers still contain valuable information.
You're looking for the grow method.
let mut vec = vec![1i,2,3];
vec.grow(4, &10);
println!("{}", vec);
Or a combination of grow and clear.
You can browse the docs here: http://static.rust-lang.org/doc/master/std/vec/struct.Vec.html

Resources