【问题标题】:Rust: Trait RangeBounds cannot be made into an objectRust:无法将 Trait RangeBounds 制成对象
【发布时间】:2020-12-31 09:46:40
【问题描述】:

我在尝试 Rust 时偶然发现了一个问题,这可能表明我对它的概念有更大的不理解。

我的目标是编写康威生命游戏的变体。我希望在创建单元格或保持活动状态时的值不是硬编码,而是在结构中。我的第一次尝试是创建一个结构

use std::ops::Range;

struct Rules {
    be_born: Range<usize>,
    stay_alive: Range<usize>,
}

impl Rules {
  pub fn new(be_born: Range<usize>, stay_alive: Range<usize>) -> Rules {
    Rules { be_born, stay_alive }
  }
}

let rules = Rules::new(2..4, 3..6);

此对象稍后在迭代所有单元格的算法中使用。它工作正常,直到我还想在创建过程中允许其他类型的范围,例如 RangeTo (2..=3)。

我知道我可以将struct Rules 重写为通用的。

use std::ops::RangeBounds;

struct Rules<BR: RangeBounds<usize>, AR: RangeBounds<usize>> {
    be_born: BR,
    stay_alive: AR,
}

这反过来又会迫使我使我使用的所有算法也变得通用。仅仅包含两个简单的范围,这似乎是相当多的开销。

另一方面,我将RangeBounds 类型的变量直接包含到我的结构中的尝试都没有成功。我尝试了&amp;dyn RangeBounds&lt;usize&gt;Box&lt;&amp;dyn RangeBounds&lt;usize&gt;&gt;,只是为了始终得到错误 E0038,即我无法将此特征转化为对象。

还有其他方法可以完成这项工作,还是有其他我看不到的可行方法?

提前感谢您的所有提示。

【问题讨论】:

  • 不要使用 RangeBounds 作为类型,而是尝试使用它作为边界:struct Rules&lt;T: RangeBounds&gt; {be_born: T, stay_alive: T}
  • @IvanC 你不能。它需要有一个泛型类型参数,或者作为 struct Rules 的另一个泛型参数 - 这涉及使用 PhantomData- 或作为像 usize 这样的 const 参数。

标签: rust trait-objects


【解决方案1】:

要获得广泛的答案,我们需要知道您对 be_bornstay_alive 字段进行迭代的准确程度。但是为了解决您指出要使用不同类型范围的问题,最简单的方法是指定be_bornstay_alive 字段都是Iterable,在迭代时返回usize,即@987654328 @:

struct Rules<T, U> 
where
    T: Iterator<Item=usize>,
    U: Iterator<Item=usize>
{
    be_born: T,
    stay_alive: U,
}

impl<T, U> Rules<T, U>
where
    T: Iterator<Item=usize>,
    U: Iterator<Item=usize>
{
    pub fn new(be_born: T, stay_alive: U) -> Self {
        Self { be_born, stay_alive }
    }
}

fn main() {
    let rule = Rules::new(2..4, 3..6);
    let other_rule = Rules::new(2..=4, 3..=6);
    let another_rule = Rules::new(2..=4, 3..6);

    for x in rule.be_born {
        println!("born: {}", x);
    }
    for y in rule.stay_alive {
        println!("alive: {}", y);
    }
}

这也将允许您将非范围但可迭代的类型分配给 be_bornstay_alive 字段。如果您只想将自己限制为范围类型,则可以将代码中的每个 Iterator&lt;Item=usize&gt; 替换为 Iterator&lt;Item=usize&gt; + RangeBounds&lt;usize&gt;,这意味着“同时实现 Iterator&lt;Item=usize&gt;RangeBounds&lt;usize&gt; 的类型”。

有关Iterator trait 的更多用法,请参阅the book

【讨论】:

  • 感谢您的回答。这不是我要找的,但你隐含地给出了我需要的答案:我完全走错了路,我可以在避免泛型的同时存储特征对象。对于我的实际问题,我需要重新考虑如何构建程序。所以谢谢你让我回到正确的轨道上。
  • @RüdigerLudwig 欢迎您。仅当您无法使用泛型做您想做的事情时才使用动态特征对象,泛型更容易处理并且通常提供更快的运行时。
猜你喜欢
  • 2017-05-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-02-28
  • 1970-01-01
  • 2021-05-10
  • 1970-01-01
相关资源
最近更新 更多