代码之家  ›  专栏  ›  技术社区  ›  Richard Neumann

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

  •  0
  • Richard Neumann  · 技术社区  · 3 年前

    我有这个代码

    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)
        }
    }
    

    然而,编译器告诉我正在使用一个不稳定的功能:

    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`.
    

    但当我去掉这个特质时。。。

    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)
        }
    }
    

    …它想让我添加它,这让我很困惑:

    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`.
    

    如何正确实现返回 RangeInclusive 或其 Rev 分别用于稳定Rust?中的泛型(整数)类型的迭代器?

    # 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
    
    1 回复  |  直到 3 年前
        1
  •  7
  •   kmdreko    3 年前

    要求 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>,
    ...
    

    编译器仍然抱怨 t ,但这只是因为你需要遵循相同的原则 .rev() 通过约束工作 DoubleEndedIterator 以及:

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

    然后就是松散的部分,比如添加 T: PartialOrd 所以 start > 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)
        }
    }