Compile error when trying to use increment operator - rust

During work on a side project I've tried to use an increment operator, as following:
fn main() {
let mut my_var = 5;
my_var++;
}
and received the following error:
error: expected expression, found `+`
--> src\main.rs:3:12
|
3 | my_var++;
| ^
What's wrong with my code?

Increment (++) and decrement (--) operators are not supported in Rust.
From Rust's FAQ:
Why doesn't Rust have increment and decrement operators?
Preincrement and postincrement (and the decrement equivalents), while
convenient, are also fairly complex. They require knowledge of
evaluation order, and often lead to subtle bugs and undefined behavior
in C and C++. x = x + 1 or x += 1 is only slightly longer, but
unambiguous.

Related

Rust mapping wants me to put a block

When working on a training problem for rust, I needed to take all items in a vector, square each of them, and then sum them. I realize that this is not good code and that changing it is faster than asking StackOverflow. I will be changing how this works but right now I'm just trying to learn how to use map and no examples seem to help me with this problem. This is for understanding, but if you have a more idiomatic way to code this quite simply, I would also love to see that. Here is the line of code:
let thing1 = divs.into_iter().map(|n| -> n*n).collect::<Vec<u64>>.iter().sum();
The important bit being:
divs.into_iter().map(|n| -> n*n)
Here is the error:
error: expected `{`, found `*`
--> src/lib.rs:10:51
|
10 | let thing1 = divs.into_iter().map(|n| -> n*n).collect::<Vec<u64>>.iter().sum();
| ^ expected `{`
|
help: try placing this code inside a block
|
10 | let thing1 = divs.into_iter().map(|n| -> n{ *n }).collect::<Vec<u64>>.iter().sum();
| + +
error: could not compile `challenge` due to previous error
This error persists regardless of what operation I do on n, n+1, etc. I tried doing what the complier wanted and it thought I was trying to dereference n. I don't understand why map would act this way - all examples I've seen don't use blocks in map.
You would only want to put -> for a closure to denote the return type. n*n is not a type, so the compiler tries to guess that you meant n as the return type and *n as the closure body, which could be valid syntax if the braces are added.
Simply remove the ->.

When I try to use the exponentiation operator in Rust, it gives strange results. Why?

I am trying to implement Complex-Step Differentiation in Rust. However, when raising the complex number to a power higher than 2, I get a completely different result than Julia. The algorithm works in Julia for any function but in Rust, it only works for second-order functions.
Here are the ways I raise the imaginary number to a power in both languages.
In Rust:
let x: f64 = 1.0;
let h: f64 = f64::from(1*10^-8);
println!("Result = {:?}", (num::pow(Complex::new(x,h),3));
// Complex { re: -587.0, im: 2702.0 }
In Julia:
h = 1*10^-8
x = 1
println((x+im*h)^3)
# 0.9999999999999997 + 3.000000000000001e-8im
I have no idea as to how I could do this so any help is very welcome.
Rust has no exponentiation operator.
The binary operator ^ is not exponentiation, but bitwise exclusive-or. This is an operation defined only for integer types, and it returns the number whose set of set bits is the symmetric difference of the sets of set bits of the operands. 1 * 10 ^ -8 thus computes (assuming the 32-bit signed type, which is what type inference assigns to this expression by default) 0x0000000a ⊕ 0xfffffff8, which is 0xfffffff2, i.e. −14.
If you want to specify a floating-point number in exponential notation, you can use the E notation:
let h: f64 = 1e-8;
For arbitrary exponentiation, since you already have the num crate, you might as well use num::pow.

Factorial if statement expect '()' found integer

I'm new to rust (coming from programming in c/c++ and python) so to learn I'm writing some basic functions. Below I have a factorial function that takes in a signed integer and has two if checks for it.
fn factorial(x: i32) -> i32 {
let result = if x > 1 {
x * factorial(x-1)
} else if x <= 1 {
1
};
result
}
To my knowledge, the if and else-if blocks should handle every case for it. However, when compiling it throws the following error:
error[E0317]: `if` may be missing an `else` clause
--> src/main.rs:22:12
|
22 | } else if x <= 1 {
| ____________^
23 | | 1
| | - found here
24 | | };
| |_____^ expected `()`, found integer
|
= note: `if` expressions without `else` evaluate to `()`
= help: consider adding an `else` block that evaluates to the expected type
error: aborting due to previous error
For more information about this error, try `rustc --explain E0317`.
error: could not compile `functions`
If I replace the else-if with just an else, it compiles just fine. Why do I need to replace it with an else? Shouldn't the previous else-if be good enough?
As the error message says, if an if expression doesn't have an else then the type of the expression is (). This is because the expression can only have one type, and there is no sensible default value in the general case for if the condition evaluated to false - that's what else is for!
In your case, the compiler could have figured out that the two predicates are in fact exhaustive. It doesn't, and that really is just how it is. If the compiler could detect exhaustiveness in this case it would be weird if it couldn't also detect it in other "obvious" cases. But predicates can be arbitrary expressions and it would be impossible to implement the check in the general case.
In this example, the compiler would have to analyse the body of the random function to know if the predicates are exhaustive or not:
// random(x) might return a different value each time it's called
if random(x) > 1 {
1
} else if random(x) <= 1 {
2
} // Not exhaustive!
Being consistent seems like the best choice for the language, since you can always add an else at the end.

Why can I start a slice past the end of a vector in Rust?

Given v = vec![1,2,3,4], why does v[4..] return an empty vector, but v[5..] panics, while both v[4] and v[5] panic? I suspect this has to do with the implementation of slicing without specifying either the start- or endpoint, but I couldn't find any information on this online.
This is simply because std::ops::RangeFrom is defined to be "bounded inclusively below".
A quick recap of all the plumbing: v[4..] desugars to std::ops::Index using 4.. (which parses as a std::ops::RangeFrom) as the parameter. std::ops::RangeFrom implements std::slice::SliceIndex and Vec has an implementation for std::ops::Index for any parameter that implements std::slice::SliceIndex. So what you are looking at is a RangeFrom being used to std::ops::Index the Vec.
std::ops::RangeFrom is defined to always be inclusive on the lower bound. For example [0..] will include the first element of the thing being indexed. If (in your case) the Vec is empty, then [0..] will be the empty slice. Notice: if the lower bound wasn't inclusive, there would be no way to slice an empty Vec at all without causing a panic, which would be cumbersome.
A simple way to think about it is "where the fence-post is put".
A v[0..] in a vec![0, 1, 2 ,3] is
| 0 1 2 3 |
^
|- You are slicing from here. This includes the
entire `Vec` (even if it was empty)
In v[4..] it is
| 0 1 2 3 |
^
|- You are slicing from here to the end of the Vector.
Which results in, well, nothing.
while a v[5..] would be
| 0 1 2 3 |
^
|- Slicing from here to infinity is definitely
outside the `Vec` and, also, the
caller's fault, so panic!
and a v[3..] is
| 0 1 2 3 |
^
|- slicing from here to the end results in `&[3]`
While the other answer explains how to understand and remember the indexing behavior implemented in Rust standard library, the real reason why it is the way it is has nothing to do with technical limitations. It comes down to the design decision made by the authors of Rust standard library.
Given v = vec![1,2,3,4], why does v[4..] return an empty vector, but v[5..] panics [..] ?
Because it was decided so. The code below that handles slice indexing (full source) will panic if the start index is larger than the slice's length.
fn index(self, slice: &[T]) -> &[T] {
if self.start > slice.len() {
slice_start_index_len_fail(self.start, slice.len());
}
// SAFETY: `self` is checked to be valid and in bounds above.
unsafe { &*self.get_unchecked(slice) }
}
fn slice_start_index_len_fail(index: usize, len: usize) -> ! {
panic!("range start index {} out of range for slice of length {}", index, len);
}
How could it be implemented differently? I personally like how Python does it.
v = [1, 2, 3, 4]
a = v[4] # -> Raises an exception - Similar to Rust's behavior (panic)
b = v[5] # -> Same, raises an exception - Also similar to Rust's
# (Equivalent to Rust's v[4..])
w = v[4:] # -> Returns an empty list - Similar to Rust's
x = v[5:] # -> Also returns an empty list - Different from Rust's, which panics
Python's approach is not necessarily better than Rust's, because there's always a trade-off. Python's approach is more convenient (there's no need to check if a start index is not greater than the length), but if there's a bug, it's harder to find because it doesn't fail early.
Although Rust can technically follow Python's approach, its designers decided to fail early by panicking in order that a bug can be faster to find, but with a cost of some inconvenience (programmers need to ensure that a start index is not greater than the length).

Why can't the compiler parse "a as u32 < b" or similar?

The following code appears to be trivial and unambiguous (Playground):
let a: u16 = 5;
let b: u32 = 10;
let c = a as u32 < b;
Yet the compiler (as of 2017-05-30) fails with a syntax error:
error: expected one of `!`, `(`, `+`, `,`, `::`, `<`, or `>`, found `;`
--> src/main.rs:6:25
|
6 | let c = a as u32 < b;
|
What is wrong with the compiler?
Note: The latest Rust compilers now provide a more useful error message (#42578):
error: `<` is interpreted as a start of generic arguments for `u32`, not a comparison
--> src/main.rs:6:22
|
6 | let c = a as u32 < b;
| -------- ^ -- interpreted as generic arguments
| | |
| | not interpreted as comparison
| help: try comparing the casted value: `(a as u32)`
This is a known compiler issue (#22644). Simply put, since a type (u32) was followed by <, the compiler attempted to parse < as the beginning of a type parameter list. Hence, the compiler was expecting something like u32 < b >, which would be syntactically valid, even though it doesn't make sense. However, an example that makes perfectly valid Rust is foo as Rc < fmt::Debug >, and if the syntax was too eager to make < the less-than operator, this one would fail just the same.
Of course, technically there are ways around it: C++ and C# have had the same ambiguity from the beginning, they just happen to have a combination of means to disambiguate these cases:
different syntax;
symbol tables at the parser level;
or some form of look-ahead.
Any of these will either have implications in the complexity of the parser or in the complexity of the language's syntax definition. The inclusion of those mechanisms in Rust could lead to breaking changes in the syntax (or probably just the rustc syntax crate).
As there is currently no active discussion to address this issue, a fairly simple and long-term solution is to wrap the cast around parentheses:
let c = (a as u32) < b;

Resources