Compilation error for nightly trait commonly used by stable std?

I do not understand how I'm supposed to use a nightly only trait in my code (using stable toolchain) like std is doing:

use std::str::FromStr;

fn values<T>(start: &str, end: &str) -> Vec<T>
where
    T: FromStr,
    <T as FromStr>::Err: std::fmt::Debug,
{
    // collection to accumulate values in
    let mut values: Vec<_> = Vec::new();

    // retrieve 'start' / 'end' of range
    let start = start.parse().unwrap();
    let end = end.parse().unwrap();

    // method 1
    for value in start..end {
        values.push(value)
    }

    //method 2
    let range = start..end;
    values.extend(range);

    //return
    values
}

Playground

Both method returns the same error:

error[E0277]: the trait bound `T: Step` is not satisfied
  --> src/lib.rs:22:12
   |
22 |     values.extend(range);
   |            ^^^^^^ the trait `Step` is not implemented for `T`
   |
   = note: required because of the requirements on the impl of `Iterator` for `std::ops::Range<T>`
help: consider further restricting this bound
   |
5  |     T: FromStr + Step,
   |                ^^^^^^

error[E0277]: the trait bound `T: Step` is not satisfied
  --> src/lib.rs:16:18
   |
16 |     for value in start..end {
   |                  ^^^^^^^^^^ the trait `Step` is not implemented for `T`
   |
   = note: required because of the requirements on the impl of `Iterator` for `std::ops::Range<T>`
   = note: required because of the requirements on the impl of `IntoIterator` for `std::ops::Range<T>`
   = note: required by `into_iter`
help: consider further restricting this bound
   |
5  |     T: FromStr + Step,
   |                ^^^^^^

The main problem is that Step is only available in nightly: documentation

Turning my function signature to:

fn values<T>(start: &str, end: &str) -> Vec<T>
where
    T: FromStr + Step,
    <T as FromStr>::Err: std::fmt::Debug,
{
    /* ... */
}

leads to following error on stable toolchain:


error[E0658]: use of unstable library feature 'step_trait': recently redesigned
 --> src/lib.rs:6:18
  |
6 |     T: FromStr + Step,
  |                  ^^^^
  |
  = note: see issue #42168 <https://github.com/rust-lang/rust/issues/42168> for more information

Standard library is perfectly able to make Range stable even if its Iterator implementation needs nightly only Step trait.

fn main() {
    // Here the range 0..11 is turned into an iterator requiring Step trait
    // Step trait is implemented for u8
    // Compilation without any error on stable toolchain
    for i in 0u8..11 {
        println!("{}", i);
    }
}

How can I write my generic values function for all primitive integers on stable toolchain? (all implements Step trait)

You can't use nightly-only features on the stable toolchain. That's why they are nightly-only.

1 Like

Do I have a workaround then?
Why std library is able to use them ?

You can use the nightly toolchain.

I don't know which rules allow that but because those features are not stable yet, you shouldn't rely on them in your code. Standart library can change or delete them in the future without changing the stable API, so there isn't any problem if only std lib itself uses them. If you just want to experiment with those features you can use the nightly compiler.

1 Like

Because it is always built with nightly. Well, not with the same nightly we can use ourselves, the real workflow is a little more complicated, but that's the gist of it.

4 Likes

You can't use Step, but your function can constrain the stable aspect, where Range<T>: Iterator<Item = T>.

If you want to allow more generic T, including types outside the standard library that can't implement unstable Step, you could use num-iter.

5 Likes