[英]Rust: macro to keep same frame rate does not work
為了保持一定的幀速率,我一直在使用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
作為一個額外的好處,如果你寫了一個語法錯誤,它會在編譯代碼時失敗,而不是在擴展宏時,這更容易調試。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.