Rust 1.45發佈:修復了Cast Unsoundness並穩定了Web框架Rocket的支持

Rust 1.45修復了一個長期存在的浮點數強制轉換問題,該問題可能導致未定義行爲(undefined behaviour )異常,並穩定了流行 Web框架Rocket所使用的特性。

將浮點數轉換爲整數時,Rest會拋出一個 未定義行爲(undefined behaviour)的已知異常。如果你對Rust的 value proposition有所瞭解的話,可能會對此感到驚訝。具體來說,下面的代碼片段雖然編譯時不會報錯,但由於使用了 cast ( as ) 將浮點數300強制轉換爲8位無符號整數(僅表示值介於0到255之間的整數),在Rust 1.44中會拋出未定義行爲的異常:

fn cast(x: f32) -> u8 { 
    x as u8 
} 
fn main() { 
    let f = 300.0; 
    let x = cast(f); 
    println!("x: {}", x); 
} 

在底層,這個問題與LLVM的 fptoui 指令有關,該指令在上述情況下使用會生成一個“有毒”的值。回想一下,Rust提供了 unsafe 關鍵字來標記希望 掛起Rust安全保證的代碼塊。上面所示的代碼片段雖然沒有被標記爲不安全,但它卻包含了不安全的代碼,這違背了Rust作爲安全語言的承諾。

Rust團隊花了幾年的時間來修復這個不健全的強制轉換問題,主要是因爲不清楚怎樣才能正確地處理它。最終,他們決定讓 as 執行“saturating”強制轉換,這意味着將過大的浮點數強制轉換爲可表示的最大整數,將過小的浮點數和NaN強制轉換爲0。此外,他們還引入了一種新的 unsafe 強制轉換,如果你想要跳過Rust的安全行爲可以使用如下代碼:

let x: f32 = 1.0; 
let y: u8 = unsafe { x.to_int_unchecked() }; 

雖然saturating強制轉換提供了一種處理溢出的安全方法,但從數學角度來看,它仍然會產生錯誤的結果。 這就是爲什麼as 在Rust中不被視爲值間轉換的慣用方法,並且還被Rust的Clipply linter標記的原因。在Rust中,將浮點數轉換爲整數更慣用的方法是,使用 into 來進行不會出錯的強制轉換,而使用 try_into 來進行可能會出錯的強制轉換。

Rust 1.45還在三個新地方增加了對調用過程宏的支持,即:作爲表達式的一部分、在模式匹配中或作爲語句。過程宏在Rust 1.30中進行了擴展,以支持類函數宏的定義(即看起來像函數的宏)。例如,下面的代碼片段定義了一個 sql 宏,該宏可生成解析SQL語句所需的Rust語法樹:

// 解析SQL語句 
let sql = sql!(SELECT * FROM posts WHERE id=1); 
#[proc_macro] 
pub fn sql(input: TokenStream) -> TokenStream { 
   ... 
} 

該變更版本的重要性還和 它在Rocket中的使用有關,Rocket是一個流行的聲明式Web框架,它使用了幾個僅在nightly Rust中可用的實驗特性。由於Rocket非常受歡迎,Rust團隊一直在努力穩定其中的一些特性,而Rocket則移除了其他的一些特性。作爲這一努力的結果,尚未發佈的Rocket 0.5將成爲首個能夠使用穩定的Rust進行編譯的Rocket版本。

除了本文提到的內容之外,Rust 1.45還包含了許多其他特性的穩定和修復。 請不要錯過官方發佈的詳細說明。

原文鏈接:

Rust 1.45 Fixes Cast Unsoundness and Stabilizes Support for Web Framework Rocket

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章