我有一个寻路算法库,以及一个测试模块,它以图形方式显示算法所采用的每一步。我们的想法是,应该能够有条件地编译算法的测试或库。因此,算法对象应保持精简,不存储也不返回测试之外不需要的任何数据。
目前我正在使用文本文件作为中间存储,只要它们发生就将步骤写入其中。当搜索完成时,测试模块从那里读取它们。
测试模块是算法模块的子代。
是否有更好的中间存储?有可能获得静态可变载体的一些方法吗?我还阅读了有关任务本地存储的内容,但没有记录好。
编辑:
不幸的是,这样的事情似乎不起作用:
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 `#`
}
}
}
答案 0 :(得分:1)
对于像这样的条件定义,您需要使用属性表单,而不是宏。那是
#[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!
宏只会扩展为true
或false
,具体取决于配置是否匹配,即两个分支都不会被删除,并且类型检查(等)仍然会发生,这就是为什么它不起作用:其中一个结构初始化与定义不匹配。
但是,我认为有更高级别的方法,它们都非常相似,但要点是始终使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
:如果它处于&#34;发布模式&#34;,则会被忽略,如果它处于&#34;调试模式&#34;,它将被注册。
这有一个不幸的缺点,需要仿制药等(可以通过谨慎使用来改善;
- cfg
例如#[cfg(demo)] impl JumpPointSearch<DebugSteps> { fn new() -> JumpPointSearch<DebugSteps> { ... } }
+与#[cfg(not(demo))]
对应的ReleaseSteps
。
- 默认类型参数,例如struct JumpPointSearch<St = ReleaseSteps> { ... }
(这些仍然是实验性的)
这种方法允许您通过在Steps
特征中提供更多钩子来轻松扩展诊断(例如,您可以提供记录更昂贵的计算信息的选项,并且具有三个级别{{1 }:release,debug和super-debug)。
Step
&#34; generics&#34; 另一个选项是使用上一部分中定义的类型cfg
以固定方式选择cfg
或DebugSteps
,即:
ReleaseSteps
如果您不需要可扩展性并且很乐意在编译时进行固定选择,这是我推荐的方法:您根本不需要很多#[cfg(demo)]
use Steps = DebugSteps;
#[cfg(not(demo))]
use Steps = ReleaseSteps;
struct JumpPointSearch {
closed_set: Vec<Node>,
open_set: PriorityQueue<Node>,
steps: Steps
}
个(只是两个以上,可能还有两个,具体取决于您处理从#[cfg]
字段中提取数据的方式),并且您不必抛出大量的泛型。
两个小问题:
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(...) {} }
。