In Rust, what is the idiomatic equivalent of Haske

2019-04-04 02:04发布

问题:

This question already has an answer here:

  • How do I include the end value in a range? 2 answers

How do I produce a list containing all the integers in Rust? I'm looking for the equivalent of Haskell's [n..m] or Python's range(n, m+1) but can't find anything.

I'm aware of the int::range function and thought it was what I was looking for, but it is made to iterate over a range, not to produce it.

回答1:

Note that this answer pertains to a pre-1.0 version of Rust and does not apply for 1.0. Specifically, std::iter::range and std::iter::range_inclusive were removed.

As of Rust 1.0.0-alpha, the easiest way to accomplish this is to use the convenience functions provided in the module std::iter: range and range_inclusive, which return iterators generating a list of numbers in the range [low, high) or [low, high], respectively.

In addition, you can build a vector from an iterator using the collect method:

use std::iter::range_inclusive;
let first_hundred: Vec<i32> = range_inclusive(1, 100).collect();
println!("upper bound inclusive: {:?}, exclusive: {:?}",
         first_hundred,
         range(101, 201).collect::<Vec<_>>());

Note that the return value of collect has its type explicitly specified in both its uses above. Normally, the Rust compiler can infer the types of expressions without an explicit specification, but collect is one of the most common cases for which the type cannot be fully inferred, in this case because it can't infer a concrete type that implements the trait FromIterator<A>, the return type of collect.

The type of a generic return value can be specified either as an explicit type in a let definition statement or inline by using the function::<Type>() syntax. Since inference fails only due to not knowing a concrete type implementing FromIterator<A>, it's possible, when explicitly specifying a generic type, to leave "holes" for type arguments which will be inferred, signified by _. This is done with the second call to collect above—in the expression Vec<_>, it's explicitly specified that the container receiving elements from collect is a Vec<T>, but the compiler figures out what exact type T must be. Currently, integers whose types are left unspecified and can't be inferred fall back to i32 (32-bit machine integer) as a default.



回答2:

It is now possible to use .. in Rust:

let vec: Vec<_> = (n .. m + 1).collect();

gives you a Vec from all the numbers from n to m.

As noted in the comment by Shepmaster, beware, it will not work if you need a range up to the maximum value of the type (255 for u8).



回答3:

Note that this answer pertains to a pre-1.0 version of Rust and does not apply for 1.0. Specifically, Vec::from_fn was removed.

There's probably nothing really idiomatic as of now. There is a handful of convenience functions to construct vectors, for example you can use Vec::from_fn:

Vec::from_fn(m+1-n, |i| i+n)


回答4:

Since Rust 1.26.0 you can use the RangeToInclusive (..=) operator to generate an inclusive range.

let v: Vec<_> = (n..=m).collect()


标签: rust