gpt4 book ai didi

rust - 在库模块和它的测试模块之间共享数据

转载 作者:行者123 更新时间:2023-11-29 08:30:34 30 4
gpt4 key购买 nike

我有一个寻路算法库,以及一个以图形方式显示算法所采取的每一步的测试模块。这个想法是人们应该能够有条件地编译算法测试或库。因此,算法对象应保持精简,不存储也不返回任何在测试之外不需要的数据。

目前我使用一个文本文件作为中间存储,每当它们发生时就将这些步骤写入其中。搜索完成后,测试模块会从那里读取它们。

测试模块是算法模块的子模块。

有没有更好的中间存储?也许有某种方法可以获得静态可变向量?我还阅读了一些有关任务本地存储的内容,但没有很好地记录。

编辑:

不幸的是,这样的事情似乎不起作用:

pub struct JumpPointSearch {
closed_set: Vec<Node>,
open_set: PriorityQueue<Node>,
#[cfg(demo)] steps: Vec<(Point2<uint>,Point2<uint>)>
}

impl JumpPointSearch {
pub fn new() -> JumpPointSearch {
if cfg!(demo) {
JumpPointSearch {
closed_set: Vec::with_capacity(40),
open_set: PriorityQueue::with_capacity(10),
steps: Vec::new()
}
} else {
JumpPointSearch { // error: missing field: `steps`
closed_set: Vec::with_capacity(40),
open_set: PriorityQueue::with_capacity(10),
}
}
}
}

这也行不通:

pub struct JumpPointSearch {
closed_set: Vec<Node>,
open_set: PriorityQueue<Node>,
#[cfg(demo)] steps: Vec<(Point2<uint>,Point2<uint>)>
}

impl JumpPointSearch {
pub fn new() -> JumpPointSearch {
JumpPointSearch {
closed_set: Vec::with_capacity(40),
open_set: PriorityQueue::with_capacity(10),
#[cfg(demo)] steps: Vec::new()
// error: expected ident, found `#`
}
}
}

最佳答案

对于这样的条件定义,您需要使用属性形式,而不是宏。也就是

#[cfg(demo)]
pub fn new() -> JumpPointSearch {
JumpPointSearch {
closed_set: Vec::with_capacity(40),
open_set: PriorityQueue::with_capacity(10),
steps: Vec::new()
}
}
#[cfg(not(demo))]
pub fn new() -> JumpPointSearch {
JumpPointSearch {
closed_set: Vec::with_capacity(40),
open_set: PriorityQueue::with_capacity(10),
}
}

cfg!宏只是扩展到 truefalse取决于配置是否匹配,也就是说,两个分支都没有被消除,并且类型检查(等)仍然对两者进行,这就是它不起作用的原因:其中一个结构初始化与定义不匹配。


但是,我认为有更高层次的方法来解决这个问题,它们非常相似,但要点是拥有 JumpPointSearch实现总是一样的,并且只有steps字段更改。

真正的泛型

struct ReleaseSteps;

struct DebugSteps {
steps: Vec<(Point2<uint>, Point2<uint>)>
}

trait Step {
fn register_step(&mut self, step: (Point<uint>, Point<uint>));
}

impl Step for ReleaseSteps {
#[inline(always)] // ensure that this is always 0 overhead
fn register_step(&mut self, step: (Point<uint>, Point<uint>)) {}
}

impl Step for DebugSteps {
fn register_step(&mut self, step: (Point<uint>, Point<uint>)) {
self.steps.push(step)
}
}

struct JumpPointSearch<St> {
closed_set: Vec<Node>,
open_set: PriorityQueue<Node>,
steps: St
}

impl<St: Step> JumpPointSearch<St> {
fn new(step: St) -> JumpPointSearch<St> { ... }
}

然后,每当您更新 steps之前,只需调用register_step : 如果它处于“ Release模式”,它将被忽略,如果它处于“ Debug模式”,它将被注册。

这有一个不幸的缺点,需要泛型等(可以通过谨慎使用来改善;- cfg例如#[cfg(demo)] impl JumpPointSearch<DebugSteps> { fn new() -> JumpPointSearch<DebugSteps> { ... } } + 对应的#[cfg(not(demo))]ReleaseSteps .- 默认类型参数,例如struct JumpPointSearch<St = ReleaseSteps> { ... } (这些仍然是实验性的)

这种方法允许您通过在 Steps 中提供更多 Hook 来轻松扩展诊断。特征(例如,您可以提供一个选项来记录计算成本更高的信息,并具有三个级别的 Step :发布、调试和 super 调试)。

cfg “泛型”

另一种选择是将上一节中定义的类型与 cfg 一起使用选择 DebugStepsReleaseSteps以一种固定的方式,即:

#[cfg(demo)]
use Steps = DebugSteps;
#[cfg(not(demo))]
use Steps = ReleaseSteps;

struct JumpPointSearch {
closed_set: Vec<Node>,
open_set: PriorityQueue<Node>,
steps: Steps
}

如果您不需要可扩展性并且乐于在编译时进行固定选择,这是我推荐的方法:您不需要很多 #[cfg]完全没有 s(只有上面两个,可能还有 2 个,具体取决于您处理从 steps 字段中提取数据的方式)并且您不必到处乱扔泛型。

两个小点:

  • 使用use这样就可以了 Steps::new()工作,意味着你可以写 Steps任何你需要的类型。 (其他两种可能性有问题:使用结构字段,即 #[cfg(demo)] steps: DebugSteps ,都失败了;使用 #[cfg(demo)] type Steps = DebugSteps; 还不允许 Steps::new() 。)
  • 你也可以删除 Steps这一个的特征,只是impl直接方法,即:impl ReleaseSteps { fn new() -> ReleaseSteps { ... } fn register_steps(...) {} }同样对于 DebugSteps .

关于rust - 在库模块和它的测试模块之间共享数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24587270/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com