Rust compound declaration - rust

In C you can delcare a bunch of similar variables at once:
int a=1, b=2, c=3;
How would you do this in rust? I can do something like:
let (mut a, mut b, mut c) = (1i, 2i, 3i);
But this requires stating mut and i multiple times. Is there a shorter way to do this?

There isn't a shorter way to do this.
Well, that's not quite true. You could define a macro:
#![feature(macro_rules)]
macro_rules! multi_mut_let {
( $( $id: ident = $value: expr ),* ) => {
let ( $( mut $id, )* ) = ($( $value, )*);
}
}
fn main() {
multi_mut_let!(a = 1i, b = 2u, c = 3f64);
a += 1;
b *= 2;
c -= 3.0;
println!("{} {} {}", a, b, c); // 2 4 0
// edge cases (which are handled fine):
multi_mut_let!();
multi_mut_let!(_x = 2u);
}
Those with sharp eyes will notice the comma is placed slightly strangely in the RHS of the macro expansion, since it results in a trailing comma on both sides of the let. This allows the second edge case to be handled correctly. Without the trailing comma, it expands to let (mut _x) = (2u);, but parens like that are not (yet) allowed in patterns; with the trailing comma it expands to let (mut _x,) = (2u,);, which are 1-tuples, and so the pattern matching is fine.

Related

Changing the variables in Rust [duplicate]

In Rust, in order to change the value of a mutable variable, what is the difference in let x = 12 or x = 12 in the following sample code?
fn main() {
let mut x: i32 = 8;
{
println!("{}", x);
let x = 12; // what if change to x = 12
println!("{}", x);
}
println!("{}", x);
let x = 42;
println!("{}", x);
}
The output is 8, 12, 8, 42. If I change let x = 12 to x = 12 ...
fn main() {
let mut x: i32 = 8;
{
println!("{}", x);
x = 12;
println!("{}", x);
}
println!("{}", x);
let x = 42;
println!("{}", x);
}
The output is 8, 12, 12, 42.
I understand that Rust uses let to do variable binding, so the let x = 12 is a variable rebinding and the binding is only valid inside a scope. But how to explain the functionality of x = 12 and the corresponding scope? Is that a type of variable binding?
The second let x introduces a second binding that shadows the first one for the rest of the block. That is, there are two variables named x, but you can only access the second one within the block statement after the let x = 12; statement. These two variables don't need to have the same type!
Then, after the block statement, the second x is out of scope, so you access the first x again.
However, if you write x = 12; instead, that's an assignment expression: the value in x is overwritten. This doesn't introduce a new variable, so the type of the value being assigned must be compatible with the variable's type.
This difference is important if you write a loop. For example, consider this function:
fn fibonacci(mut n: u32) -> u64 {
if n == 0 {
return 1;
}
let mut a = 1;
let mut b = 1;
loop {
if n == 1 {
return b;
}
let next = a + b;
a = b;
b = next;
n -= 1;
}
}
This function reassigns variables, so that each iteration of the loop can operate on the values assigned on the preceding iteration.
However, you might be tempted to write the loop like this:
loop {
if n == 1 {
return b;
}
let (a, b) = (b, a + b);
n -= 1;
}
This doesn't work, because the let statement introduces new variables, and these variables will go out of scope before the next iteration begins. On the next iteration, (b, a + b) will still use the original values.

Detect duplicated elements of a string slice happening in order

I need to detect and list string characters of slice that repeat themselves in order more or equal than N times. I managed to write non-higher-order-function solution in Rust already (below), but I wonder if this can be simplified to chaining iter methods.
The idea:
let v = "1122253225";
let n = 2;
Output:
There are 2 repetition of '1'
There are 3 repetition of '2'
There are 2 repetition of '2'
Indexes where repetition happens are not important. Repetition must happen in order (ie. 3 repetition of '2' separated by other values from the other 2 repetition of '2' counts as separate output lines).
My non-iterator solution:
let mut cur_ch = '\0';
let mut repeat = 0;
for ch in v.chars() {
if ch == cur_ch {
repeat = repeat + 1;
}
else {
if repeat >= n {
printf!("There are {} repetition of '{}'", repeat, cur_ch);
}
cur_ch = ch;
repeat = 1;
}
}
if repeat >= n {
printf!("There are {} repetition of '{}'", repeat, cur_ch);
}
It works, but is there a better way to do so with chaining iter methods?
Here is a solution that uses scan and filter_map:
fn main() {
let s = "112225322555";
let n = 2;
let i = s
.chars()
.map(|v| Some(v))
.chain(std::iter::once(None))
.scan((0, None), |(count, ch), v| match ch {
Some(c) if *c == v => {
*count += 1;
Some((None, *count))
}
_ => Some((ch.replace(v), std::mem::replace(count, 1))),
})
.filter_map(|(ch, count)| match ch {
Some(Some(ch)) if count >= n => Some((ch, count)),
_ => None,
});
for (ch, num) in i {
println!("There are {} repititions of {}", num, ch);
}
}
Playground Link
The first step is to use scan to count the number of adjacent characters. The first argument to scan is a state variable, which gets passed to each call of the closure that you pass as the second argument. In this case the state variable is a tuple containing the current character and the number of times it has been seen.
Note:
We need to extend the iteration one beyond the end of the string we are analyzing (otherwise we would miss the case where the end of the string contained a run of characters meeting the criteria). We do this by mapping the iteration into Option<char> and then chaining on a single None. This is better than special-casing a character such as \0, so that we could even count \0 characters.
For the same reason, we use Option<char> as the current character within the state tuple.
The return value of scan is an iterator over (Option<Option<char>>, i32). The first value in the tuple will be None for each repeated character in the iterator, whereas at each boundary where the character changes it will be Some(Some(char))
We use replace to both return the current character and count, at the same time as setting the state tuple to new values
The last step is to use filter_map to:
remove the (None, i32) variants, which indicate no change in the incoming character
filter out the cases where the count does not reach the limit n.
Here's one attempt at using filter_map():
fn foo(v: &str, n: usize) -> impl Iterator<Item = (usize, char)> + '_ {
let mut cur_ch = '\0';
let mut repeat = 0;
v.chars().chain(std::iter::once('\0')).filter_map(move |ch| {
if ch == cur_ch {
repeat += 1;
return None;
}
let val = if repeat >= n {
Some((repeat, cur_ch))
} else {
None
};
cur_ch = ch;
repeat = 1;
val
})
}
fn main() {
for (repeat, ch) in foo("1122253225", 2) {
println!("There are {} repetition of '{}'", repeat, ch);
}
}
And then you can generalize this to something like this:
fn foo<'i, I, T>(v: I, n: usize) -> impl Iterator<Item = (usize, T)> + 'i
where
I: Iterator<Item = T> + 'i,
T: Clone + Default + PartialEq + 'i,
{
let mut cur = T::default();
let mut repeat = 0;
v.chain(std::iter::once(T::default()))
.filter_map(move |i| {
if i == cur {
repeat += 1;
return None;
}
let val = if repeat >= n {
Some((repeat, cur.clone()))
} else {
None
};
cur = i;
repeat = 1;
val
})
}
This would be higher-order, but not sure if it's actually much simpler than just using a for loop!

Partial Application Macro in Rust, Works But

So I was writing (attempting) some variadic macros to try to implement compose and curry in rust. pipe was easy enough.
Variadic partial application though? Not so much. Props to anyone who can come up with a solution for this partial application macro that doesn't use those pesky seemingly ignorable type args (and maybe variadic? w/o reflection I think it's impossible):
//ltr compose for closures
macro_rules! pipe {
($init:tt |> $($fn:ident),+) => {{
let mut r = $init;
$( r = $fn(r); )*
r
}}
}
//partially apply a closure w/ up to 4 args
macro_rules! apply {
($fn:ident<$t1:ty,$t2:ty>($arg1:expr)) => {
|x:$t2| $fn($arg1 as $t1, x)
};
($fn:ident<$t1:ty,$t2:ty,$t3:ty>($arg1:expr)) => {
|x:$t2, y:$t3| $fn($arg1 as $t1,x, y)
};
($fn:ident<$t1:ty,$t2:ty,$t3:ty>($arg1:expr, $arg2:expr)) => {
|x:$t3| $fn($arg1 as $t1,$arg2 as $t2,x)
};
($fn:ident<$t1:ty,$t2:ty,$t3:ty,$t4:ty>($arg1:expr)) => {
|x: $t2, y:$t3, z:$t4| $fn($arg1 as $t1, x, y, z)
};
($fn:ident<$t1:ty,$t2:ty,$t3:ty,$t4:ty>($arg1:expr, $arg2:expr)) => {
|x:$t3, y:$t4| $fn($arg1 as $t1,$arg2 as $t2, x, y)
};
($fn:ident<$t1:ty,$t2:ty,$t3:ty,$t4:ty>($arg1:expr, $arg2:expr, $arg3:expr)) => {
|x:$t4| $fn($arg1 as $t1,$arg2 as $t2,arg3 as $t3,x)
};
}
fn main() {
let add = |x:i32, y:i32| x + y;
let sq = |x:i32| x * x;
let dbl = |x:i32| x * 2;
//blargh i hate those typeargs! i need them for the matcher
//to get the original params number and type since rust has no reflection :(
//weirdly if i ignore them with _ it works. But it will luckily fail
//hard if you supply incorrect args.
let plus1 = apply!(add<_,_>(1));
let r = pipe!(3 |> dbl, plus1, sq);
print!("{}", r);
}
Edit: The reason I seemingly cannot do variadic args on this is because that changes the structure of the closure. Seemed fine at first glance, I'd just wrap it in a match statement based on the total params and difference between the number of exprs vs total params. but if you try to return closures of varying signatures in a match arm it won't compile. The good news is this approach is probably low-overhead. But its really not a great improvement over partial application thru inline closures as necessary:
//simple, works, no type args or even type declarations on params I'm just a crazy person who wants it all!
let add = |x, y| x + y;
let add1 = |x| add(x, 1);
So its really just an academic pursuit at this point, it hardly seems practical
I am not sure whether or not I understand your question, but I think maybe this library may help you: https://docs.rs/partial_application/0.2.0/partial_application/
#[macro_use]
extern crate partial_application;
//ltr compose for closures
macro_rules! pipe {
($init:tt |> $($fn:ident),+) => {{
let mut r = $init;
$( r = $fn(r); )*
r
}}
}
fn main() {
let add = |x:i32, y:i32| x + y;
let sq = |x:i32| x * x;
let dbl = |x:i32| x * 2;
//blargh i hate those typeargs! i need them for the matcher
//to get the original params number and type since rust has no reflection :(
//weirdly if i ignore them with _ it works. But it will luckily fail
//hard if you supply incorrect args.
let plus1 = partial!(add => 1,_);
let r = pipe!(3 |> dbl, plus1, sq);
print!("{}", r);
}
You may refer to this library to create your own macro.

Is it possible to query the stack space of a closure?

fn test<T>(t: T) {
println!("size of: {}", std::mem::size_of::<T>());
}
fn main() {
let f = || {
let i1: i32 = 0;
let i2: i32 = 0;
let i3: i32 = 0;
i1 + i2 + i3
};
test(f) // prints "size of: 0"
}
A non move closure always seems to prints that the size is 0 probably because it is just inlined.
A move closure gets bigger with every variable that it captures but I wonder if it is possible to query the stack space that a closure requires?
Update:
I want to create something like a Coroutine<F>. I need to know the size of F for it to be executed. I currently allocate 1mb per coroutine which is way too much. So I was wondering if it would be possible to determine the actual size that I need to allocate.
I misunderstood the question, so the following text does not really answer OP's question!
Yes, you can measure the size of a closure. The sizes are just a bit confusing sometimes. Let's test all kinds of closures:
let constant = || 27;
let no_capture = |x: i32| 27 + x;
let a = vec![3];
let immut_capture = || a[0] + 27;
let immut_capture_arg = |x: i32| a[0] + x;
let mut b = vec![3];
let mut c = vec![3];
let mut_capture = || { b[0] += 27; b[0] };
let mut_capture_arg = |x: i32| { c[0] += x; c[0] };
let mut d = vec![3];
let mut e = vec![3];
let move_capture = move || { d[0] += 27; d.into_boxed_slice() };
let move_capture_arg = move |x: i32| { e[0] += x; e.into_boxed_slice() };
When I print their sizes with std::mem::size_of_val (which is roughly equivalent to your hand-written test() function), I get the following results:
constant -> 0
no_capture -> 0
immut_capture -> 8
immut_capture_arg -> 8
mut_capture -> 8
mut_capture_arg -> 8
move_capture -> 24
move_capture_arg -> 24
You can try it yourself with this code on playground.
So whats up with those results?
A closure is a type that saves its environment – either by reference or by value. Mutable and immutable reference to sized data have the same size, namely size_of::<usize>(), usually 8. This explains the size of the closures that capture the outer variable by reference.
The move closures on the other hand, capture their environment by value, which means that they have to save the environment inside themselves. So it's no surprise that their sizes are equal to size_of::<Vec<_>>().
What about the closures with size 0? Since they are not capturing any environment, they could be ordinary fn-functions, too. And I guess that Rust turns them into fn-functions. And in fact, if we try to print the size of an fn-item (not a function pointer!) like this:
fn foo(x: i32) -> i32 { x + 27 }
println!("{}", std::mem::size_of_val(&foo));
... we get 0!

Rust use of moved value

When using below function:
fn factors(number: &BigInt) -> Vec<BigInt> {
let mut n = number.clone();
let mut i: BigInt = ToBigInt::to_bigint(&2).unwrap();
let mut factors = Vec::<BigInt>::new();
while i * i <= n {
if (n % i) == ToBigInt::to_bigint(&1).unwrap() {
i = i + ToBigInt::to_bigint(&1).unwrap();
}
else {
n = n/i as BigInt;
factors.push(i);
}
i = i + ToBigInt::to_bigint(&1).unwrap();
}
if n > i {
factors.push(n);
}
factors
}
I get moved value errors for literally every time i or n is used, starting from the line with while, also in the if. I have read about borrowing, which I understand decently, but this thing I don't understand.
I am not "copying" the value at all, so I don't see anywhere were I could lose ownership of the variables.
Mul (and the other arithmetic operators) take the parameters by value, so i * i move the value i (this is not a problem for primitive numbers because they implement Copy - BigInt does not).
As Mul is implemented for (two) &BigInt, you can do the multiplication (and the other arithmetic operations) with &:
use num::*;
fn factors(number: &BigInt) -> Vec<BigInt> {
let mut n = number.clone();
let mut i = BigInt::from(2);
let mut factors = Vec::new();
while &i * &i <= n {
if (&n % &i) == BigInt::one() {
i = i + BigInt::one();
} else {
n = n / &i;
factors.push(i.clone());
}
i = i + BigInt::one();
}
if n > i {
factors.push(n);
}
factors
}
Note that I also made some simplifications, like omitting the type on Vec::new and using BigInt::from (cannot fail).
Remember that operators in Rust are just syntactic sugar for function calls.
a + b translates to a.add(b).
Primitive types such as i32 implement the trait Copy. Thus, they can be copied into such an add function and do not need to be moved.
I assume the BigInt type you are working with does not implement this trait.
Therefore, in every binary operation you are moving the values.

Resources