如何在稳定的 Rust 中编写返回 RangeInclusive 或其反向迭代器的函数?

Ric*_*ann 0 traits rust

我有这个代码

use std::iter::Step;

fn main() {
    for i in mkiter(25, 20) {
        println!("{}", i);
    }
    for i in mkiter(10, 23) {
        println!("{}", i);
    }
}

fn mkiter<T>(start: T, end: T) -> Box<dyn Iterator<Item = T>>
where
    T: Step,
{
    if start > end {
        Box::new((end..=start).rev())
    } else {
        Box::new(start..=end)
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,编译器告诉我我正在使用不稳定的功能:

error[E0658]: use of unstable library feature 'step_trait': recently redesigned
 --> main.rs:1:5
  |
1 | use std::iter::Step;
  |     ^^^^^^^^^^^^^^^
  |
  = note: see issue #42168 <https://github.com/rust-lang/rust/issues/42168> for more information

error[E0658]: use of unstable library feature 'step_trait': recently redesigned
  --> main.rs:13:10
   |
13 | where T: Step
   |          ^^^^
   |
   = note: see issue #42168 <https://github.com/rust-lang/rust/issues/42168> for more information

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0658`.
Run Code Online (Sandbox Code Playgroud)

但是当我移除特质限制时...

fn main() {
    for i in mkiter(25, 20) {
        println!("{}", i);
    }
    for i in mkiter(10, 23) {
        println!("{}", i);
    }
}

fn mkiter<T>(start: T, end: T) -> Box<dyn Iterator<Item = T>> {
    if start > end {
        Box::new((end..=start).rev())
    } else {
        Box::new(start..=end)
    }
}
Run Code Online (Sandbox Code Playgroud)

...它要我添加它,这让我很困惑:

error[E0369]: binary operation `>` cannot be applied to type `T`
  --> main.rs:11:14
   |
11 |     if start > end {
   |        ----- ^ --- T
   |        T
   |
help: consider restricting type parameter `T`
   |
10 | fn mkiter<T: std::cmp::PartialOrd>(start: T, end: T) -> Box<dyn Iterator<Item = T>> {
   |            ++++++++++++++++++++++

error[E0599]: the method `rev` exists for struct `RangeInclusive<T>`, but its trait bounds were not satisfied
   --> main.rs:12:32
    |
12  |         Box::new((end..=start).rev())
    |                                ^^^ method cannot be called on `RangeInclusive<T>` due to unsatisfied trait bounds
    |
   ::: /home/rne/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ops/range.rs:345:1
    |
345 | pub struct RangeInclusive<Idx> {
    | ------------------------------ doesn't satisfy `RangeInclusive<T>: Iterator`
    |
    = note: the following trait bounds were not satisfied:
            `T: Step`
            which is required by `RangeInclusive<T>: Iterator`
            `RangeInclusive<T>: Iterator`
            which is required by `&mut RangeInclusive<T>: Iterator`
help: consider restricting the type parameter to satisfy the trait bound
    |
10  | fn mkiter<T>(start: T, end: T) -> Box<dyn Iterator<Item = T>> where T: Step {
    |                                                               +++++++++++++

error[E0277]: the trait bound `T: Step` is not satisfied
  --> main.rs:14:9
   |
14 |         Box::new(start..=end)
   |         ^^^^^^^^^^^^^^^^^^^^^ the trait `Step` is not implemented for `T`
   |
   = note: required for `RangeInclusive<T>` to implement `Iterator`
   = note: required for the cast from `RangeInclusive<T>` to the object type `dyn Iterator<Item = T>`
help: consider restricting type parameter `T`
   |
10 | fn mkiter<T: std::iter::Step>(start: T, end: T) -> Box<dyn Iterator<Item = T>> {
   |            +++++++++++++++++

error: aborting due to 3 previous errors

Some errors have detailed explanations: E0277, E0369, E0599.
For more information about an error, try `rustc --explain E0277`.
Run Code Online (Sandbox Code Playgroud)

如何正确实现一个函数,该函数分别为稳定 Rust 中的泛型(整数)类型返回一个RangeInclusive或其迭代器?Rev

# rustc --version                                                                                                                                                 2023-05-24 03:34:14
rustc 1.69.0 (84c898d65 2023-04-16)
# rustup update stable                                                                                                                                            2023-05-24 03:34:04
info: syncing channel updates for 'stable-x86_64-unknown-linux-gnu'

  stable-x86_64-unknown-linux-gnu unchanged - rustc 1.69.0 (84c898d65 2023-04-16)

info: self-update is disabled for this build of rustup
info: any updates to rustup will need to be fetched with your system package manager
Run Code Online (Sandbox Code Playgroud)

kmd*_*eko 7

要求这T: Step只是达到目的的一种手段,你实际上并不关心是否T实现Step,你只关心它RangeInclusive<T>是一个生成的迭代器T。你可以准确地表达这一点:

fn mkiter<T>(start: T, end: T) -> Box<dyn Iterator<Item = T>>
where
    RangeInclusive<T>: Iterator<Item = T>,
...
Run Code Online (Sandbox Code Playgroud)

编译器仍然抱怨Tand Step,但这只是因为您也需要遵循相同的原则才能.rev()通过约束 on 来工作DoubleEndedIterator

fn mkiter<T>(start: T, end: T) -> Box<dyn Iterator<Item = T>>
where
    RangeInclusive<T>: Iterator<Item = T> + DoubleEndedIterator,
...
Run Code Online (Sandbox Code Playgroud)

然后就剩下一些未解决的问题,例如添加T: PartialOrdsostart > end有效,并添加生命周期以绕过'static默认返回Box<dyn ...>. 这是最终的代码:

fn mkiter<'a, T: 'a>(start: T, end: T) -> Box<dyn Iterator<Item = T> + 'a>
where
    T: PartialOrd,
    RangeInclusive<T>: Iterator<Item = T> + DoubleEndedIterator,
{
    if start > end {
        Box::new((end..=start).rev())
    } else {
        Box::new(start..=end)
    }
}
Run Code Online (Sandbox Code Playgroud)