I find using (1..4)
fn main() {
for v in (1..4) {
println!("{}", v);
}
}
and {1..4}
fn main() {
for v in {1..4} {
println!("{}", v);
}
}
gets the same result. Is there any different semantics between "(1..4)
" and "{1..4}
" iteration?
An iterator is responsible for the logic of iterating over each item and determining when the sequence has finished. When you use iterators, you don't have to reimplement that logic yourself. In Rust, iterators are lazy, meaning they have no effect until you call methods that consume the iterator to use it up.
You can make your iterator peekable and peek the first item; if it's None , then the iterator is empty.
The code only looks slow when un-commenting the for loop because it does not do anything otherwise. Iterators are lazy, and only perform some activity when consumed. A for loop is an example of a construct which consumes the iterator. Calling .
Rust supports four loop expressions: A loop expression denotes an infinite loop. A while expression loops until a predicate is false. A while let expression tests a pattern.
They produce the same iterators. You can even omit parentheses/braces:
fn main() {
for v in 1..4 {
println!("{}", v);
}
}
You can enclose an expression with ()
or {}
in general. There is a difference however: {}
creates a block and you can write statements (like let
) in it. There is also a very subtle difference in how expressions are parsed. Edit: I found a blog article that describes another difference in how coercion and borrowck works.
Usually ()
is preferred if you don't need statements.
There's no real useful difference. Both parenthesis and braces count as a single expression and function to alter the precedence. I'm pretty sure they have slightly different parsing rules, but at that point I'd guess there's a cleaner way of writing the code.
Note that in your examples, the idiomatic way would be to use neither:
fn main() {
for v in 1..4 {
println!("{}", v);
}
}
When needed, I feel I've only ever seen parenthesis used, never braces:
fn main() {
println!("{}", (1..4).count());
}
There are rare cases where curly braces provide more power. Since they serve to start a new scope, you can use them to "manually" transfer ownership in some tricky locations. For the purposes of the simple iterator described, there won't be any visible difference.
In addition to the existing answers I was interested what the difference would be in the mid-level IR.
Even though the braces introduce a new block, in this case there is virtually no difference even in the (Nightly) MIR - the compiler immediately recognizes that the block serves no other purpose than returning a Range
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With