簡體   English   中英

Rust:保持相同幀率的宏不起作用

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM