Assign a single value to multiple variables in one line in Rust? - rust

A common way to assign multiple variables is often expressed in programming languages such as C or Python as:
a = b = c = value;
Is there an equivalent to this in Rust, or do you need to write it out?
a = value;
b = value;
c = value;
Apologies if this is obvious, but all my searches lead to Q&A regarding tuple assignment.

No, there is no equivalent. Yes, you have to write multiple assignments, or write a macro which itself does multiple assignments.

You cannot chain the result of assignments together. However, you can assign multiple variables with a single statement.
In a let statement, you can bind multiple names by using an irrefutable pattern on the left side of the assignment:
let (a, b) = (1, 2);
(Since Rust 1.59, you can also have multiple values in the left side of any assignment, not just let statements.)
In order to assign the same value to multiple variables without repeating the value, you can use a slice pattern as the left-hand side of the assignment, and an array expression on the right side to repeat the value, if it implements Copy:
let value = 42;
let [a, b, c] = [value; 3]; // or: let [mut a, mut b, mut c] = ...
println!("{} {} {}", a, b, c); // prints: 42 42 42
(Playground)

Using const generics:
fn main() {
let [a, b, c] = fill_new_slice(1);
dbg!(a, b, c);
}
fn fill_new_slice<T: Copy, const N: usize>(value: T) -> [T; N] {
[value; N]
}
$ cargo run --quiet
[src/main.rs:3] a = 1
[src/main.rs:3] b = 1
[src/main.rs:3] c = 1

Actually, you can totally do this!
let a # b # c = value;
This uses the # syntax in patterns, which is used to bind a value to a variable, but keep pattern matching. So this binds value to a (by copy), and then continues to match the pattern b # c, which binds value to b, and so on.
But please don't. This is confusing and of little to no benefit over writing multiple statements.

In Rust, the expression a = b = c = value; is the same to a = (b = (c = value));
And the (x = ...) returns (). Then, the first expression is an equivalent of the following:
c = value;
b = ();
a = ();
Note that the expression has a semicolon in the end, but if the expression were in the last line as a function's return like this a = b = c = value, the equivalente would be the following:
c = value;
b = ();
a = () // without the semicolon

Related

In rust, why does s[0..] returns a type of `str`?

In my understanding, s[0..] calls the method ops::Index::index. I try to call s.index(0..), but find that it returns a type of &str. The code is as follows
let a = String::from("hello world");
let b = &a;
let c = b.index(1..);
println!("{}", c);
let d = b[1..];
println!("{}", d);
This code will display an error, and indicate that the variable d is of type str.
What do I understand wrong? and how to understand the [] and index() in rust?
In the documentation of std::ops::Index, we find:
container[index] is actually syntactic sugar for *container.index(index)
and
This allows nice things such as let value = v[index] if the type of value implements Copy.
In your example, c has type &str as you expect, but d would be the dereference (*) of such an &str; this would lead to str which is rejected by the compiler (not sized).
In order to obtain a &str in d, you could write:
let d = &b[1..]; // & was missing
which is really explicit because it clearly states: «I want to refer to something which stands inside b».
Here is another example of the implicit dereference (*) in a different context:
let mut arr = [1, 2, 3, 4];
let n = arr[1]; // not *arr[1]
arr[2] += n; // not *arr[2]
println!("{:?}", arr); // [1, 2, 5, 4]

What is & doing in a rust for in loop? [duplicate]

This question already has an answer here:
What is the difference between `e1` and `&e2` when used as the for-loop variable?
(1 answer)
Closed 1 year ago.
Trying to understand how & works in a rust for..in loop...
For example let's say we have something simple like a find largest value function which takes a slice of i32's and returns the largest value.
fn largest(list: &[i32]) -> i32 {
let mut largest = list[0];
for item in list {
if *item > largest {
largest = *item;
}
}
largest
}
In the scenario given above item will be an &i32 which makes sense to me. We borrow a slice of i32's and as a result the item would also be a reference to the individual item in the slice. At this point we can dereference the value of item with * which is what I assume how a pointer based language would work.
But now if we alter this slightly below...
fn largest(list: &[i32]) -> i32 {
let mut largest = list[0];
for &item in list {
if item > largest {
largest = item;
}
}
largest
}
If we put an & in front of item this changes item within the for..in into an i32... Why? In my mind this is completely counterintuitive to how I would have imagined it to work. This to me says, "Give me an address/reference to item"... Which in itself would already be a reference. So then how does item get dereferenced? Is this just a quirk with rust or am I fundamentally missing something here.
All variable assignments in Rust, including loop variables in for loops and function arguments, are assigned using pattern matching. The value that is being assigned is matched against the target pattern, and Rust tries to fill in the "blanks", i.e. the target variable names, in a way that substituting the values makes the pattern match the value. Let's look at a few examples.
let x = 5;
This is the simplest case. Obvious, substituting x with 5 makes both sides match.
if let Some(x) = Some(5) {}
Here, x will also become 5, since substituting that value into the pattern will make both side identical.
let &x = &5;
Again, the two sides match when setting x to 5.
if let (Some(&x), &Some(y)) = (Some(&5), &Some(6)) {}
This assignment results in x = 5 and y = 6, since substituting these values into the pattern makes both sides match.
Let's apply this to your for loop. In each loop iteration, the pattern after for is matched against the next value returned by the iterator. We are iterating an &[i32], and the item type of the resulting iterator is &i32, so the iterator yields a &i32 in each iteration. This reference is matched against the pattern &item. Applying what we have seen above, this means item becomes an i32.
Note that assigning a value of a type that does not have the Copy marker trait will move that value into the new variable. All examples above use integers, which are Copy, so the value is copied instead.
There is no magic here, pure logic. Consider this example:
let a = 1;
let b = &a; // b is a reference to a
let &c = &a; // c is a copy of value a
You can read the third line of the example above as "Assign reference to a to a reference to c". This basically creates a virtual variable "reference to c", assigns to it the value &a and then dereferences it to get the value of c.
let a = 1;
let ref_c = &a;
let c = *ref_c;
// If you try to go backwards into this assignments, you get:
let &c = &a;
let &(*ref_c) = &a;
let ref_c = &a; // which is exactly what it was
The same occurs with the for .. in syntax. You iterate over item_ref, but assign them to &item, which means that the type of item is Item.
for item_ref in list {
let item = *item_ref;
...
}
// we see that item_ref == &item, so above is same as
for &item in list {
...
}

How to write multiple condition in if let statement?

How to modify if let statement so it also handles another condition like Some(7) == b?
let a = Some(6);
let b = Some(7);
if let Some(6) = a /* && Some(7) = b */{
// do something
}
You can use a simple tuple:
if let (Some(6), Some(7)) = (a, b) {
// do something
}
The if let expression only admits one match arm pattern against one expression. However, they can be merged together into a single equivalent pattern match condition. In this case, the two Option values can be combined into a pair and matched accordingly.
if let (Some(6), Some(7)) = (a, b) {
// do something
}
Playground
See also:
Simplest way to match multiple fields of a struct against `None`

Ocaml struct like we do in C

I want to write a recursive struct, like we do in C, but in Ocaml.
I want we contains a boolean and a list of recursive copies of elements of the same type.
How can I do that in Ocaml?
OCaml type declarations are recursive by default. So there's nothing special to do to get something like you describe. If you literally want a list inside your struct, you can define something like this:
type mystruct = { b: bool; others: mystruct list }
If you want a "linked list" of structures of your given type, you could define something more like this:
type mystruct2 = { b: bool; rest : mystruct2 option }
One key here is that the rest element is an option type so that your list can end at some point.
There are many other ways to define this basic structure. A more idiomatic OCaml definition might be to use a variant type:
type mylist = Last | Node of bool * mylist
This last type isn't exactly equivalent because a value of your described type always contains at least one boolean, and this type has a value (Last) with no booleans. In practice this usually turns out to be what you want.
Update
Here are two top-level variables of each of these types. In each pair the first is as small as possible and the second is a little larger.
let v10 = { b = true; others = []}
let v11 = { b = false; others = [ {b = true; others = []} ] }
let v20 = { b = true; rest = None }
let v21 = { b = false; rest = Some { b = true; rest = None } }
let v30 = Last
let v31 = Node (true, Last)
If you have basic questions like this, it might be worthwhile to work through an OCaml tutorial, maybe one of those listed here: https://ocaml.org/learn/tutorials/

Is there a way to pass named arguments to format macros without repeating the variable names?

With new versions of Rust, you can simplify structure initialization like this:
Foo {
a: a,
b: b,
}
to this
Foo { a, b }
Is it possible to do something similar for format!/println!-like macros?
For now I need to write it like this:
let a = "a";
let b = "b";
write!(file, "{a} is {b}", a = a, b = b).unwrap();
Is it possible to write my own macros with an API like this:
let a = "a";
let b = "b";
my_write!(file, "{a} is {b}", a, b).unwrap();
RFC 2795 has been accepted and implemented. Starting in Rust 1.58, you will be able to go beyond your desired syntax:
write!(file, "{a} is {b}").unwrap();
Before then, you can write your own wrapper around println! and friends:
macro_rules! myprintln {
($fmt:expr, $($name:ident),*) => { println!($fmt, $($name = $name),*) }
}
fn main() {
let a = "alpha";
let b = "beta";
myprintln!("{a} is {b}", a, b);
}
This will likely always be limited compared to the full formatter macro, but it may be sufficient for your case.
As of 1.5 this is the closest you can get natively.
my_write!(file, "{} is {}", a, b).unwrap();
Additionally as Shepmaster pointed out my answer will eventually become obsolete (I'll try to remember to remove it when that happens). If you want to keep an eye on the (to be implemented) syntax they propose you can check this github ticket they linked

Resources