rust - Rust:保持相同帧速率的宏不起作用
问题描述
为了保持一定的帧速率,我一直在std::thread::sleep()
等待足够的时间过去。计算它的睡眠时间会使代码有点混乱,所以我尝试为它制作一个宏。现在就是这样,但它不起作用:
macro_rules! fps30 {
($($body: expr;);*) => {
let time = std::time::Instant::now()
$($body)*
let time_elapsed = time.elapsed().as_micros();
if FRAME_TIME_30FPS_IN_MICROS > time_elapsed {
let time_to_sleep = FRAME_TIME_30FPS_IN_MICROS - time_elapsed;
std::thread::sleep(std::time::Duration::from_micros(time_to_sleep as u64));
}
};
}
我想像这样使用它:
loop {
fps30!{
// do everything I want to do in the loop
}
}
当我不将它实现为宏时(通过直接将代码粘贴到循环中),它可以工作,并且每秒保持 29 帧(我猜不是 30 帧,因为睡眠计算的开销很小)。它在编译期间给出的错误状态是:no rules expected the token 'p'
,p
我在宏中使用的对象/结构实例在哪里。
有什么建议么?
解决方案
问题在于对;
in 的处理:
$($($body: expr;);*)
当你想接受一个;
单独的表达式列表时,你应该写$($($body: expr;)*)
或$($($body: expr);*)
。前者表示以 - 结尾的;
表达式列表,而后者是 -;
分隔表达式的列表。
差异是微妙但重要的。如果同时添加两者,则需要编写两个;;
来分隔每个表达式。
如果您接受;
终止的表达式列表会更好,所以这样做:
$($($body: expr;)*)
然后你在宏的主体中有几个错误,也与;
. 你错过了;
扩展之前的$body
:
let time = std::time::Instant::now();
而且您;
在自身的扩展中遗漏了$body
,因为;
不是被捕获的一部分expr
:
$($body;)*
通过这些更改,它可以工作,除非您尝试:
fps30!{
if a {
}
if a {
}
}
因为没有;
后面的if
表达式!!!您可以尝试切换到:
$($($body: expr);*)
但这也行不通,现在因为;
表达式之间没有!
您可以接受一个$body: block
,但随后您将需要编写额外的几个{}
. 不理想...
如果您真的想接受任何类型的代码块,我建议您接受令牌树列表( tt
)。并且在扩展它们时,将它们括在 a{}
中,以防它不以 a 结尾;
。
macro_rules! fps30 {
($($body: tt)*) => {
let time = std::time::Instant::now();
{ $($body)* }
let time_elapsed = time.elapsed().as_micros();
//...
};
}
现在您的宏将接受任何类型的语法,并将在宏内部无声地扩展它。
您甚至可以添加$body
具有类型和值的可能性,并对该值进行fps30
评估:
let res = { $($body)* };
//...
res
作为一个额外的好处,如果你写了一个语法错误,它会在编译代码时失败,而不是在扩展宏时,这更容易调试。
推荐阅读
- r - 在R中的两个条件下合并两列
- optimization - MT5ForConditionalGeneration 与 Pytorch-lightning 给出 attribute_error
- android - getStringExtra() 函数返回 Intent { (有额外) }
- tensorflow - 带有张量流的 ImportError
- python - 如何手动从数组中选择值
- machine-learning - 训练人脸检测器/分类器的合适方法是什么?
- python - 计算图像中两个像素之间的距离
- c# - net core 5.0 .FirstOrDefault()' 无法翻译
- html - 有没有一种方法可以通过单击图像将您带到使用超链接的页面?
- sql - 为什么我的结果中不能包含另一个表中的列?