In Rust, this code compiles and runs but generates no error or output:
fn main() {
for number in 4..1 {
println!("{}!", number);
}
}
Shouldn't Rust consider this as invalid code and not compile or give a warning since it also doesn't seem to understand that I want to iterate in reverse?
This code generates no Assembly output.
Let's see what happens internally.
4..1
is actually just syntactical sugar for
std::ops::Range { start: 4, end: 1 }
Which is defined as:
The range start..end contains all values with start <= x < end. It is empty if start >= end.
Therefore, as specified in the documentation, for 4..1 should do nothing, as it always iterates forwards and the start is already past the end.
To iterate backwards, use:
(1..4).rev()
Related
I'm in progress of learning Rust and I'm trying to apply similar style I'm using with C++. With C++ I would be using RAII and exceptions and the closest I can get with Rust is RAII combined with early return with error Result. As such, when I write code such as
fn parse_meminfo() -> Result<Meminfo, io::Error> {
// ...
let file = File::open("/proc/meminfo")?;
for line in io::BufReader::new(file).lines() {
let line = line?;
// ...
Is it possible to somehow avoid the fragment let line = line?; of code? I already tried
for line in io::BufReader::new(file).lines()?
and
for line? in io::BufReader::new(file).lines()
and
for Ok(line) in io::BufReader::new(file).lines()
and
for line in io::BufReader::new(file).lines().expect("failed to read line")
but rustc wasn't happy with any of those. First and fourth have the test in logically wrong position because ? and expect() are testing the iterator instead of the item, if I've understood correctly. Second was syntax error, and the syntax Ok(line) is not happy to ignore the error because that doesn't mean early return. I would like to have early return with the error if the iterator in the loop gives an error and adding one extra line of code just for that seems silly and that test seems a bit detached from the actual loop. Can you suggest anything better? If the let line = line?; is indeed the idiomatic style, then I guess I would have to learn to love it.
Is it possible to somehow avoid the fragment let line = line?; of code?
Depending how you're using line, you could just tack on the ? over there. expr? simply desugars to1
match expr {
Ok(v) => v,
Err(e) => return e.into()
}
So you can see how the second attempt would not work (the left hand side of the for...in is an irrefutable pattern, not an expression).
The error handling here is largely orthogonal to the iteration, and iteration doesn't (at this juncture, though it seems unlikely that'll be added) have first-class support for error signaling, so you have an Iterator<Item=Result<...>> and you handle the Result however you wish.
If you don't care for the error reporting you could always .lines().map(|v| v.expect(...) and that'll immediately panic at the first error, but I don't know that that's what you're looking for.
1: that's not quite true anymore because of the `Try` trait, but close enough still
I want to check if the result from a request is having any issue. I categorize it into two: i) server error, ii) something else that is not a success. The third category is, result actually being a success. However, in the third category, I don't want to do anything.
So, my desirable code is:
if res.status().is_server_error() {
panic!("server error!");
} else if !(res.status.is_success()){
panic!("Something else happened. Status: {:?}", res.status());
} else{
pass;
}
I am aware of other ways to achieve this result: using match, ifs instead of if else if. But I wanted to learn what is the corresponding keyword of pass, like we have in Python. My aim is: if result is successful, just move along, if not, there are two ways to handle that panic.
Behold!
if predicate {
do_things();
} else {
// pass
}
Or even better
if predicate {
do_things();
} // pass
Or as I’ve recently taken to calling it the implicit + pass system
if predicate {
do_things();
}
In all seriousness there is no pass and no need for a pass in rust. As for why it exists in python, check out this answer
Python needs pass because it uses indentation-based blocks, so it requires some syntax to "do nothing". For example, this would be a syntax error in a Python program:
# syntax error - function definition cannot be empty
def ignore(_doc):
# do nothing
count = process_docs(docs, ignore) # just count the docs
The ignore function has to contain a block, which in turn must contain at least one statement. We could insert a dummy statement like None, but Python provides pass which compiles to nothing and signals the intention (to do nothing) to the human reader.
This is not needed in Rust because Rust uses braces for blocks, so one can always create an empty block simply using {}:
// no error - empty blocks are fine
fn ignore(_doc: &Document) {
// do nothing
}
let count = process_docs(docs, ignore); // just count the docs
Of course, in both idiomatic Python and Rust, one would use a closure for something as simple as the above ignore function, but there are still situations where pass and empty blocks are genuinely useful.
The purpose of this code is to loop from 1 to 4 and stop.
My question is why if I add or leave the semicolon in the else statement (;) it doesn't matter... the code compile just fine. What's the best approach? Add the semicolon or leave it?
fn main() {
let mut var = 1;
loop{
println!("It is now {}", var);
if var >= 4 {
println!("Finished the loop");
break;
} else {
var = var + 1;
}
}
}
In general, the trailing semicolon determines the return value of the block. If you leave the semicolon out, the return value is the value of the last expression in the block. With the semicolon included, the return value is always Rust's unit value, the empty tuple () (except when the block contains an expression that does not return, in which case the return type is the "never" type !, which does not have any values).
In this particular case, there is no semantic difference. Assignment expressions return the unit value as well, i.e. (var = var + 1) == (). However, this is more or less a coincidence. You don't actually want to return any value in that statement, so including the semicolon makes your intention much clearer.
The generated binary will be exactly be the same here but don't just think about the compiler, think about the humans reading the code too.
The absence of a semicolon at the end of the last statement of a block has an implied meaning: the value is returned from the block, the value matters.
If the value isn't used, don't return it. Put that semicolon to help humans read the code.
If you don't put that semicolon and configure Clippy to be very annoying, you'll get a warning too due to the semicolon_if_nothing_returned rule.
I'm trying to figure out what this warning actually means. The program works perfectly but during compile I get this warning:
main.rs:6:1: 8:2 warning: function 'isMultiple' should have a snake case identifier,
#[warn(non_snake_case_functions)] on by default
the code is very simple:
/*
Find the sum of all multiples of 3 or 5 below 1000
*/
fn isMultiple(num: int) -> bool {
num % 5 == 0 || num % 3 == 0
}
fn main() {
let mut sum_of_multiples = 0;
//loop from 0..999
for i in range(0,1000) {
sum_of_multiples +=
if isMultiple(i) {
i
}else{
0
};
}
println!("Sum is {}", sum_of_multiples);
}
You can turn it off by including this line in your file. Check out this thread
#![allow(non_snake_case)]
Rust style is for functions with snake_case names, i.e. the compiler is recommending you write fn is_multiple(...).
My take on it is that programmers have been debating the case of names and other formatting over and over and over again, for decades. Everyone has their preferences, they are all different.
It's time we all grew up and realized that it's better we all use the same case and formatting. That makes code much easier to read for everyone in the long run. It's time to quit the selfish bickering over preferences. Just do as everyone else.
Personally I'm not much into underscores so the Rust standard upset me a bit. But I'm prepared to get use to it. Wouldn't it be great if we all did that and never had to waste time thinking and arguing about it again.
To that end I use cargo-fmt and clippy and I accept whatever they say to do. Job done, move on to next thing.
There is a method in the Rust convention:
Structs get camel case.
Variables get snake case.
Constants get all upper case.
Makes it easy to see what is what at a glance.
-ZiCog
Link to thread : https://users.rust-lang.org/t/is-snake-case-better-than-camelcase-when-writing-rust-code/36277/2
I am trying to determine what the best way is to do a CAS with atomics in c++.
My example:
atomic<int> foo(0), bar(1);
while(!foo.compare_exchange_weak(bar, 2)) {}
gives error:
no matching function for call to ‘std::atomic::compare_exchange_weak(std::atomic< int >&, int)
Essentially, what I want to do, is to have the old value of foo stored in bar, which is itself an atomic type. A solution to the above error is:
atomic<int> foo(0), bar;
int tmp = 1;
do
{
bar = tmp;
}
while(!foo.compare_exchange_weak(tmp, 2));
Which respects the contract for compare_exchange_weak, and exits the loop only when bar has the value of foo at the moment that foo becomes is set to 2.
Yet, I am unsure if this is the best way to go about it. It seems to me that the first thing I wanted to do is the correct approach. Any comments on what is suitable, and if the second solution is OK?
Thanks.
I realize this question has been up a while, but I had the same error today.
The first example is failing to compile because you are using an atomic<int> instead of just an int as an argument to compare_exchange_weak. The following compiles and runs on my pc:
atomic<int> foo(0);
int bar(1);
while(!foo.compare_exchange_weak(bar, 2)) {}
I think in the example you provided, both loops are equivalent. The problem lies in the type of the argument, not in the logic.