如何解决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
是我在宏中使用的对象/结构实例。
有什么建议吗?
解决方法
问题在于如何处理;
:
$($($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
)列表。并在展开它们时,将它们括在{}
中,以防它不以;
结尾。
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
作为额外的好处,如果您编写语法错误,则在编译代码时(而不是在扩展宏时)将失败,这很容易调试。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。