Let &mut syntax - syntax

It is possible to make the following binding in Rust:
let &mut a = &mut 5;
But what does it mean exactly? For example, let a = &mut 5 creates an immutable binding of type &mut i32, let mut a = &mut 5 creates a mutable binding of type &mut i32. What about let &mut?

An easy way to test the type of something is to assign it to the wrong type:
let _: () = a;
In this case the value is an "integral variable", or a by-value integer. It is not mutable (as testing with a += 1 shows).
This is because you are using destructuring syntax. You are pattern matching your &mut 5 against an &mut _, much like if you wrote
match &mut 5 { &mut a => {
// rest of code
} };
Thus you are adding a mutable reference and immediately dereferencing it.
To bind a mutable reference to a value instead, you can do
let ref mut a = 5;
This is useful in destructuring to take references to multiple inner values.

Related

Random string generator with minimal allocations

I want to generate a large file of pseudo-random ASCII characters given the parameters: size per line and number of lines. I cannot figure out a way to do this without allocating new Strings for each line. This is what I have: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=42f5b803910e3a15ff20561117bf9176
use rand::{Rng, SeedableRng};
use std::error::Error;
fn main() -> Result<(), Box<dyn Error>> {
let mut data: Vec<u8> = Vec::new();
write_random_lines(&mut data, 10, 10)?;
println!("{}", std::str::from_utf8(&data)?);
Ok(())
}
fn write_random_lines<W>(
file: &mut W,
line_size: usize,
line_count: usize,
) -> Result<(), Box<dyn Error>>
where
W: std::io::Write,
{
for _ in 0..line_count {
let mut s: String = rand::rngs::SmallRng::from_entropy()
.sample_iter(rand::distributions::Alphanumeric)
.take(line_size)
.collect();
s.push('\n');
file.write(s.as_bytes())?;
}
Ok(())
}
I'm creating a new String every line, so I believe this is not memory efficient. There is fn fill_bytes(&mut self, dest: &mut [u8]) but this is for bytes.
I would preferably not create a new SmallRng for each line, but it is used in a loop and SmallRng cannot be copied.
How can I generate a random file in a more memory and time efficient way?
You can easily reuse a String in a loop by creating it outside the loop and clearing it after using the contents:
// Use Kevin's suggestion not to make a new `SmallRng` each time:
let mut rng_iter =
rand::rngs::SmallRng::from_entropy().sample_iter(rand::distributions::Alphanumeric);
let mut s = String::with_capacity(line_size + 1); // allocate the buffer
for _ in 0..line_count {
s.extend(rng_iter.by_ref().take(line_size)); // fill the buffer
s.push('\n');
file.write(s.as_bytes())?; // use the contents
s.clear(); // clear the buffer
}
String::clear erases the contents of the String (dropping if necessary), but does not free its backing buffer, so it can be reused without needing to reallocate.
See also
Weird behaviour when using read_line in a loop
Why does Iterator::take_while take ownership of the iterator? explains why by_ref is needed
This modification of your code does not allocate any Strings and also does not construct a new SmallRng each time, but I have not benchmarked it:
fn write_random_lines<W>(
file: &mut W,
line_size: usize,
line_count: usize,
) -> Result<(), Box<dyn Error>>
where
W: std::io::Write,
{
// One random data iterator.
let mut rng_iter = rand::rngs::SmallRng::from_entropy()
.sample_iter(rand::distributions::Alphanumeric);
// Temporary storage for encoding of chars. If the characters used
// are not all ASCII then its size should be increased to 4.
let mut char_buffer = [0; 1];
for _ in 0..line_count {
for _ in 0..line_size {
file.write(
rng_iter.next()
.unwrap() // iterator is infinite so this never fails
.encode_utf8(&mut char_buffer)
.as_bytes())?;
}
file.write("\n".as_bytes())?;
}
Ok(())
}
I am new to Rust so it may be missing some ways to tidy it up. Also, note that this writes only one character at a time; if your W is more expensive per operation than an in-memory buffer, you probably want to wrap it in std::io::BufWriter, which will batch writes to the destination (using a buffer that needs to be allocated, but only once).
I (MakotoE) benchmarked Kevin Reid's answer, and it seems their method is faster though memory allocation seems to be the same.
Benchmarking time-wise:
#[cfg(test)]
mod tests {
extern crate test;
use test::Bencher;
use super::*;
#[bench]
fn bench_write_random_lines0(b: &mut Bencher) {
let mut data: Vec<u8> = Vec::new();
data.reserve(100 * 1000000);
b.iter(|| {
write_random_lines0(&mut data, 100, 1000000).unwrap();
data.clear();
});
}
#[bench]
fn bench_write_random_lines1(b: &mut Bencher) {
let mut data: Vec<u8> = Vec::new();
data.reserve(100 * 1000000);
b.iter(|| {
// This is Kevin's implementation
write_random_lines1(&mut data, 100, 1000000).unwrap();
data.clear();
});
}
}
test tests::bench_write_random_lines0 ... bench: 764,953,658 ns/iter (+/- 7,597,989)
test tests::bench_write_random_lines1 ... bench: 360,662,595 ns/iter (+/- 886,456)
Benchmarking memory usage using valgrind's Massif shows that both are about the same. Mine used 3.072 Gi total, 101.0 MB at peak level. Kevin's used 4.166 Gi total, 128.0 MB peak.

Why can't I mutably borrow a primitive from an enum?

I would like to be able to obtain references (both immutable and mutable) to the usize wrapped in Bar in the Foo enum:
use Foo::*;
#[derive(Debug, PartialEq, Clone)]
pub enum Foo {
Bar(usize)
}
impl Foo {
/* this works */
fn get_bar_ref(&self) -> &usize {
match *self {
Bar(ref n) => &n
}
}
/* this doesn't */
fn get_bar_ref_mut(&mut self) -> &mut usize {
match *self {
Bar(ref mut n) => &mut n
}
}
}
But I can't obtain the mutable reference because:
n does not live long enough
I was able to provide both variants of similar functions accessing other contents of Foo that are Boxed - why does the mutable borrow (and why only it) fail with an unboxed primitive?
You need to replace Bar(ref mut n) => &mut n with Bar(ref mut n) => n.
When you use ref mut n in Bar(ref mut n), it creates a mutable
reference to the data in Bar, so the type of n is &mut usize.
Then you try to return &mut n of &mut &mut u32 type.
This part is most likely incorrect.
Now deref coercion kicks in
and converts &mut n into &mut *n, creating a temporary value *n
of type usize, which doesn't live long enough.
These examples show the sample problem:
fn implicit_reborrow<T>(x: &mut T) -> &mut T {
x
}
fn explicit_reborrow<T>(x: &mut T) -> &mut T {
&mut *x
}
fn implicit_reborrow_bad<T>(x: &mut T) -> &mut T {
&mut x
}
fn explicit_reborrow_bad<T>(x: &mut T) -> &mut T {
&mut **&mut x
}
The explicit_ versions show what the compiler deduces through deref coercions.
The _bad versions both error in the exact same way, while the other two compile.
This is either a bug, or a limitation in how lifetimes are currently implemented in the compiler. The invariance of &mut T over T might have something to do with it, because it results in &mut &'a mut T being invariant over 'a and thus more restrictive during inference than the shared reference (&&'a T) case, even though in this situation the strictness is unnecessary.

Speedup counter game

I'm trying to solve a Rust algorithm question on hackerrank. My answer times out on some of the larger test cases. There are about 5 people who've completed it, so I believe it is possible and I assume they compile in release mode. Is there any speed-ups I'm missing?
The gist of the game is a counter (inp in main) is conditionally reduced and based on who can't reduce it any more, the winner is chosen.
use std::io;
fn main() {
let n: usize = read_one_line().
trim().parse().unwrap();
for _i in 0..n{
let inp: u64 = read_one_line().
trim().parse().unwrap();
println!("{:?}", find_winner(inp));
}
return;
}
fn find_winner(mut n: u64) -> String{
let mut win = 0;
while n>1{
if n.is_power_of_two(){
n /= 2;
}
else{
n -= n.next_power_of_two()/2;
}
win += 1;
}
let winner =
if win % 2 == 0{
String::from("Richard")
} else{
String::from("Louise")
};
winner
}
fn read_one_line() -> String{
let mut input = String::new();
io::stdin().read_line(&mut input).expect("Failed to read");
input
}
Your inner loop can be replaced by a combination of builtin functions:
let win = if n > 0 {
n.count_ones() + n.trailing_zeros() - 1
} else {
0
};
Also, instead of allocating a string every time find_winner is called,
a string slice may be returned:
fn find_winner(n: u64) -> &'static str {
let win = if n > 0 {
n.count_ones() + n.trailing_zeros() - 1
} else {
0
};
if win % 2 == 0 {
"Richard"
} else{
"Louise"
}
}
Avoiding memory allocation can help speeding up the application.
At the moment, the read_one_line function is doing one memory allocation per call, which can be avoided if you supply the String as a &mut parameter:
fn read_one_line(input: &mut String) -> &str {
io::stdin().read_line(input).expect("Failed to read");
input
}
Note how I also alter the return type to return a slice (which borrows input): further uses here do not need to modify the original string.
Another improvement is I/O. Rust is all about explicitness, and it means that io::stdin() is raw I/O: each call to read_line triggers interactions with the kernel.
You can (and should) instead used buffered I/O with std::io::BufReader. Build it once, then pass it as an argument:
fn read_one_line<'a, R>(reader: &mut R, input: &'a mut String) -> &'a str
where R: io::BufRead
{
reader.read_line(input).expect("Failed to read");
input
}
Note:
it's easier to make it generic (R) than to specify the exact type of BufReader :)
annotating the lifetime is mandatory because the return type could borrow either parameter
Putting it altogether:
fn read_one_line<'a, R>(reader: &mut R, input: &'a mut String) -> &'a str
where R: io::BufRead
{
reader.read_line(input).expect("Failed to read");
input
}
fn main() {
let mut reader = io::BufReader::new(io::stdin());
let mut input = String::new();
let n: usize = read_one_line(&mut reader, &mut input).
trim().parse().unwrap();
for _i in 0..n{
let inp: u64 = read_one_line(&mut reader, &mut input).
trim().parse().unwrap();
println!("{:?}", find_winner(inp));
}
return;
}
with the bigger win probably being I/O (might even be sufficient in itself).
Don't forget to also apply #John's advices, this way you'll be allocation-free in your main loop!

What is the reason for requiring &mut foo instead of &foo when foo has been declared mutable?

For a C routine like
MPI_Comm_rank(MPI_Comm comm, int *rank);
The Rust foreign function interface could be declared like this:
use libc::c_int; // 0.2.79
#[link(name = "mpi")]
extern "C" {
fn MPI_Comm_rank(mpi_comm: c_int, rank: *mut c_int);
}
I call the binding like this, which works, but left me puzzled about syntax:
pub static MPI_COMM_WORLD: libc::c_int = 0x44000000;
fn main() {
let mut rank: c_int = 999999;
/* but why '&mut rank' and not simply '&rank' ? */
unsafe { MPI_Comm_rank(MPI_COMM_WORLD, &mut rank) }
}
I originally tried
unsafe { MPI_Comm_rank(MPI_COMM_WORLD, &rank) }
but this gives a compiler error:
error[E0308]: mismatched types
--> src/main.rs:12:44
|
12 | unsafe { MPI_Comm_rank(MPI_COMM_WORLD, &rank) }
| ^^^^^ types differ in mutability
|
= note: expected raw pointer `*mut i32`
found reference `&i32`
I declared 'rank' as mut, so what gives?
You’re conflating two completely distinct features.
let mut x; makes a mutable binding x, allowing you to modify what x is bound to (x = 42) and for non-reference types to modify its contents (x.y = 42). It does not control the mutability of the target of references.
This is different from the type of references you’re dealing with.
&mut T is a mutable reference and can be coerced to *mut T.
&T is an immutable reference can be coerced to *const T.
As the function you are calling wants *mut T, you must pass it a *mut T or a &mut T; *const T or &T will not do.
To be sure, you can only take a mutable reference to mutable data, so let x = 42; &mut x doesn’t work as it needs let mut x instead of let x, but that’s still entirely distinct and is a part of Rust’s rules about mutability.
Your function expects *mut c_int pointer (a mutable raw pointer), and you need to use &mut operator to obtain it. However, you can only take &mut pointer to mut variables, hence you need to declare rank variable as mut rank.
If your function expected *const c_int pointer, you would be able to use &, but this is not the case.

How do I create two new mutable slices from one slice?

I would like to take a mutable slice and copy the contents into two new mutable slices. Each slice being one half of the original.
My attempt #1:
let my_list: &mut [u8] = &mut [0, 1, 2, 3, 4, 5];
let list_a: &mut [u8] = my_list[0..3].clone();
let list_b: &mut [u8] = my_list[3..6].clone();
println!("{:?}", my_list);
println!("{:?}", list_a);
println!("{:?}", list_b);
Output:
error: no method named `clone` found for type `[u8]` in the current scope
--> src/main.rs:3:43
|
3 | let list_a: &mut [u8] = my_list[0..3].clone();
| ^^^^^
error: no method named `clone` found for type `[u8]` in the current scope
--> src/main.rs:4:43
|
4 | let list_b: &mut [u8] = my_list[3..6].clone();
| ^^^^^
My attempt #2:
let my_list: &mut [u8] = &mut [0, 1, 2, 3, 4, 5];
let list_a: &mut [u8] = my_list[0..3].to_owned();
let list_b: &mut [u8] = my_list[3..6].to_owned();
println!("{:?}", my_list);
println!("{:?}", list_a);
println!("{:?}", list_b);
Output:
error[E0308]: mismatched types
--> src/main.rs:12:29
|
12 | let list_a: &mut [u8] = my_list[0..3].to_owned();
| ^^^^^^^^^^^^^^^^^^^^^^^^ expected &mut [u8], found struct `std::vec::Vec`
|
= note: expected type `&mut [u8]`
found type `std::vec::Vec<u8>`
= help: try with `&mut my_list[0..3].to_owned()`
error[E0308]: mismatched types
--> src/main.rs:13:29
|
13 | let list_b: &mut [u8] = my_list[3..6].to_owned();
| ^^^^^^^^^^^^^^^^^^^^^^^^ expected &mut [u8], found struct `std::vec::Vec`
|
= note: expected type `&mut [u8]`
found type `std::vec::Vec<u8>`
= help: try with `&mut my_list[3..6].to_owned()`
I can use two Vec<u8> and just loop over the input and push cloned values I guess, but I was hoping there was a nicer way to do this:
extern crate rand;
use rand::{thread_rng, Rng};
fn main() {
let my_list: &mut [u8] = &mut [0; 100];
thread_rng().fill_bytes(my_list);
let list_a = &mut Vec::new();
let list_b = &mut Vec::new();
for i in 0..my_list.len() {
if i < my_list.len() / 2 {
list_a.push(my_list[i].clone());
} else {
list_b.push(my_list[i].clone());
}
}
println!("{:?}", list_a.as_slice());
println!("{:?}", list_b.as_slice());
println!("{:?}", my_list);
}
The split_at and split_at_mut methods will give you two slices, which you can then copy or even safely use without copying if borrow checker allows.
let (list_a, list_b) = my_list.split_at_mut(my_list.len()/2)
You can build vectors from slices directly by cloning the elements using multiple methods:
Vec::to_vec
From / Into
ToOwned
fn main() {
let my_list: &mut [u8] = &mut [0, 1, 2, 3, 4, 5];
let mut vec1 = my_list[0..2].to_vec();
let mut vec2: Vec<u8> = my_list[2..4].into();
let mut vec3 = my_list[2..6].to_owned();
println!("{:?}", vec1);
println!("{:?}", vec2);
}
Your original problem was caused because all of these return a Vec but you were attempting to claim that it was a slice, equivalent to:
let thing: &mut [u8] = Vec::new();
You could chain two iterators over the slices.
let my_list: &mut [u8] = &mut [0, 1, 2, 3, 4, 5];
let mut slices = my_list[0..3].iter().chain(my_list[3..6].iter());
for e in slices {}
chain will iterate over the first iterator, then the second.
To create new lists:
let my_list: &mut [u8] = &mut [0, 1, 2, 3, 4, 5];
let mut a: Vec<u8> = my_list[0..3].iter().cloned().collect();
let mut b: Vec<u8> = my_list[3..6].iter().cloned().collect();

Resources