在编译稳定代码时,为什么会收到关于缺少的不稳定特征(std :: iter :: Step-编译器不会让我实现的错误)的错误消息?

时间:2019-07-11 09:52:33

标签: rust

我想定义一个函数,该函数应允许我在一系列结构实例上返回迭代器。

我已经为标准类型尝试了相同的功能,例如usize(请参阅简化的代码示例),并且这种方法有效(尽管有点尴尬)。我不能在我所想到的场景中使用标准类型,因此这对解决方案没有帮助,但可以帮助我了解这里存在某种问题。

#[derive(Debug)]
struct MyThing();

fn main() {
    let good  = 0usize..=10usize;
    // ALSO WORKS for thing in *good.start()..=*good.end() {
    for thing in 0usize..=10usize {
        dbg!(thing);
    }
    dbg!(good);

    let bad  = MyThing()..=MyThing();
    for thing in *bad.start()..=*bad.end() {
        dbg!(thing);
    }
    dbg!(bad);
}
$ cargo --version
cargo 1.35.0 (6f3e9c367 2019-04-04)

$ cargo build
   Compiling huh v0.1.0 (huh)
error[E0277]: the trait bound `MyThing: std::iter::Step` is not satisfied
  --> src/main.rs:13:18
   |
13 |     for thing in *bad.start()..=*bad.end() {
   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::iter::Step` is not implemented for `MyThing`
   |
   = note: required because of the requirements on the impl of `std::iter::Iterator` for `std::ops::RangeInclusive<MyThing>`

我不希望稳定的编译器告诉我我缺少一个不稳定的特征。我这里可能还有其他类型的问题,我不了解,但稳定的编译器告诉我,我的问题是我尚未实现不稳定的特征。我绝对不能修复我的代码(不切换到不稳定)。

我想我想了解的是,是否有可能基于用户定义的类型定义一个范围,然后可以对其进行迭代。

任何人都可以解释发生的事情并提出解决问题的方法吗?

2 个答案:

答案 0 :(得分:4)

= note: required because of the requirements on the impl of `std::iter::Iterator` for `std::ops::RangeInclusive<MyThing>`

Step特质尚未稳定。但是,正如此错误注释所暗示的那样,它仍在内部使用; Iterator类型的Range*实现依赖于Step的实现。

其结果是,直到稳定Iterator(或某些替代API)后,您才能(尚未)为自定义类型的范围实现Step


请注意,Rust中的“不稳定”并不意味着它有故障或可能以任何方式破裂。这仅表示API将来仍有可能更改并破坏向后兼容性。 Rust编译器可以利用此类API进行语法除错,因为它可以稍后在与API更改相同的发行版中更改除错。


为解决该问题,我建议对其他内容进行迭代,可以将其转换为您的类型。您的代码可能过于简化,无法为您的实际用例提供切合实际的功能,但遵循以下原则:

impl From<usize> for Thing {
    fn from(index: usize) -> Thing {
        Thing()
    }
}

for i in 0..=10 {
    let thing = Thing::from(i);
    dbg!(thing);
}

这不会导致任何性能开销。

答案 1 :(得分:4)

目前您无法在稳定的编译器(自1.36.0版)上实现该特征。

例如在Rust世界中,这种“模式”并不少见。请参见Pattern方法中使用的str::find特性,因此您可以使用字符串,字符或闭包来搜索内容。

不稳定在此情况下表示特征的实际特征可能会发生变化,因此不稳定。如果您使用不稳定的编译器(又称夜间编译器),则会选择加入代码,因为特征的签名可能会导致代码中断。