I saw some code which looks like this:
fn test <'a> (&'a mut &'a str) {}
I know that 'a is a lifetime and that the & is a reference.
However I have trouble understanding a double reference &&.
In my understanding a reference is a pointer, so is a && a pointer to another pointer or something else?
In my understanding a reference is a pointer
Yes, a reference is just a pointer with special borrow-checking semantics. Pointers, and thus references, are just addresses in memory (and sometimes a size as well but that's irrelevant for this answer), which means that they essentially have a value of their own, separate from the value that they "point to" or "reference." That's why code like this can work:
fn main() {
let num1 = 1;
let num2 = 2;
let mut num_ref = &num1;
dbg!(num1, num2, num_ref); // num1 and num2 are 1 and 2 and num_ref is &1
num_ref = &num2;
dbg!(num1, num2, num_ref); // num1 and num2 are 1 and 2 and num_ref is &2
}
The values under the reference don't change, but the reference itself changes.
So, &mut &T is a mutable reference to an immutable reference, which means you can change the reference underneath the mutable reference:
fn make_reference_one(r: &mut &i32) {
*r = &1;
}
fn main() {
let mut num_ref = &2;
dbg!(num_ref); // is &2
make_reference_one(&mut num_ref);
dbg!(num_ref); // is now &1
}
Related
How can I convert a mutable u8 pointer to a mutable reference of another type?
let ptr: *mut u8;
let reference: &mut SomeType = ?; // What should i do here?
I have found a sort-of viable solution, but I wonder if there is a better way:
let reference = unsafe { &mut *(ptr as *mut SomeType) };
You have already found an acceptable method. A slightly preferable one is to use pointer::cast instead of as, because that explicitly specifies that you are trying to change the type of the referent and not any of the many other things as can do.
let ptr = ptr.cast::<SomeType>();
let reference = unsafe { &mut *ptr };
Do not use std::mem::transmute for this. Transmuting should always be the last resort in any circumstance (the nomicon and function documentation say so!), because it reinterprets the bytes regardless of what they are — in this case it'll convert any pointer-sized value, such as a reference to the pointer. By sticking with cast and &*, we catch more possible type errors. (Clippy even has a default lint against using transmute here.)
You could use std::mem::transmute instead:
use std::mem::transmute;
#[repr(transparent)]
struct SomeStruct(u8);
fn main() {
let a = &mut 10u8;
let ptr = a as *mut u8;
let reference: &mut SomeStruct = unsafe { transmute(ptr) };
}
To dereference a raw pointer, we must use unsafe code. What are the situations in which raw pointers can be used (and can be useful) in ways that don't involve using unsafe code at all?
Pretty much the only thing you can do is cast the raw pointer to an usize. You can use that to do stuff like getting the index in an array from a reference into the array.
fn get_index_in_array(array: &[i32], item: &i32) -> usize {
let array_ptr: *const i32 = array.as_ptr();
let item_ptr: *const i32 = item;
let distance = ((item_ptr as usize) - (array_ptr as usize)) / std::mem::size_of::<i32>();
assert!(distance < array.len());
distance
}
fn main() {
let arr = [1, 2, 3, 4];
println!("{}", get_index_in_array(&arr, &arr[2]));
}
2
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
This code:
let mut a2 = 99;
let b: *mut i32 = &mut a2;
*b = 11; // does not compile , even after unsafe {*b}
Generates the error:
error[E0133]: dereference of raw pointer requires unsafe function or block
--> src/main.rs:4:5
|
4 | *b = 11;
| ^^^^^^^ dereference of raw pointer
But this code works:
let mut a2 = 99
let b = &mut a2;
*b = 11;
What is the difference between the two?
What is the difference between the two?
One is a raw pointer (*mut _) and the other is a reference (&mut _). As the book says:
the compiler guarantees that references will never be dangling
Additionally, a reference will never be NULL. It is always safe to dereference a reference. It is not always safe to dereference a raw pointer as the compiler cannot guarantee either of those. Thus, you need an unsafe block:
unsafe { *b = 11; }
See also:
Understanding Pointer Types in Rust
References and Borrowing
Unsafe Rust
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);