當前位置:首頁 » 編程軟體 » rust編譯參數

rust編譯參數

發布時間: 2024-10-31 08:11:25

A. Rust中的String,&str和str都是什麼

本文旨在深入解析 Rust 語言中 String、&str 和 str 的本質與特性。

String 可以被視為一個由三個核心元素組成的結構體:一個指向堆上連續內存的指針,一個表示已使用內存大小的變數 len,以及一個表示內存總容量的變數 capacity。String 在被創建後會從堆上獲取內存,在被釋放前會釋放這些內存,因為它實現了 Drop trait,這意味著 String 不能實現 Copy trait。

String 內部的連續內存視作 u8 數組,確保了內部存儲的位元組序列符合 UTF-8 編碼標准。這使得 String 在處理文本數據時非常高效且可靠。

&str 是 String 的借用形式,也稱為字元串切片。通過對 String 進行 deref 操作,可以得到 &str。deref 的底層實現使用 from_utf8_unchecked 函數對 &[u8] 數據進行解釋,這類似於 C 語言中的 reinterpret_cast。因此,我們可以將 &str 和 &[u8] 看作是具有相同結構的類型。

&[T] 類型與普通的引用有所不同,它具有兩個 usize 的大小。&[T] 用於指向連續內存,並攜帶被指向內存的長度信息。從_raw_parts 函數可以創建 &'a [T] 類型,該函數接受一個指針和一個長度參數。

&str 的特殊性使其與普通的引用區分開,這種包含元數據的引用被稱為「胖指針」。*const str 和 *mut str 可以通過 &str 轉換而來,這意味著這些原始指針類型同樣具有兩個 usize 的大小。

考慮到 Rust 中的 str、[T] 以及 dyn Trait 是動態大小類型的常用表示,我們對 str 的內部組織進行了分析。str 類似於 &str,即由 u8 類型的連續內存組成,但其長度在運行時動態變化,因此無法在編譯時確定。

為了將 DST 類型的實例存儲在棧上,需要使用 Rust 的 nightly 版本並開啟 unsized_locals 特性。創建 String 實例並使用 push_str 函數動態添加數據後,可以調用 into_boxed_str 將 String 轉換為 Box。

值得注意的是,str 類型並未實現 Copy trait,這意味著不能直接拷貝 str 對象。當將 str 轉移到棧上時,Box 的解引用能夠轉移所有權,而不是簡單地調用 *boxed.deref()。這表明 str 數據被轉移到了棧上。

通過內存視圖的觀察,可以發現 str 類型實際上存儲在棧內存中,且具有動態大小。實驗結果顯示 str 佔用了 11 個位元組的內存空間,而緊隨其後的數據與 str 無關。當嘗試訪問 str 變數時,會遇到相關元數據的獲取問題。

在 Rust 中,使用 & 來訪問 DST 類型的值,而不需要像使用 &str 那樣顯式指定。這是因為 & 可以作為引用類型,而在訪問 DST 類型時需要獲取其內部的元數據。在某些情況下,例如在使用 unsized_locals 特性時,通過 & 進行訪問可以實現 DST 類型的棧上存儲。

B. Rust 宏簡記 - 以 vec! 為例

Rust 的宏,這里主要指的是 macro_rules! ,可以實現很多強有力的工具,但是畢竟跟函數實現還是不同,需要有一些額外注意的點。

這里簡要解析一下 std::vec! 的實現。此段需要讀者大致明白 vec! 的用法。

首先, #[cfg(not(test))] 表示這是一個僅在非 test 模式下才有用的宏,換言之,test 模式可能使用一個其他的宏。這里不展開此問題。

#[macro_export] 表示這個宏可以在其他的 crate 中使用。

頭部標記的剩餘兩行也不解釋。

vec! 這個宏有三種形式,第一種類似數組的定義方式。 [0; 10] 定義一個長度是 10,每個數字都是 0 的數組,相應地, vec![0; 10] 構造類似的 Vec 。

有趣的是,宏的定義中「參數」外部的括弧是小括弧,但是大多標准庫的文檔給出的實例都是中括弧。這是因為 Rust 的宏不限制「調用」的括弧是什麼,我們甚至可以選擇大括弧。而 vec! 調用時選擇中括弧的原因,只是為了讓這種語法跟構造數組的語法更相似而已。

參數列表裡的 expr 放在 $elem 的類型的位置,這從語法上,跟 Rust 函數的參數類型也是相似的。 expr 表示 $elem 需得是一個表達式(Expression),此外還有一些其他的,宏參數可以用的類型。由此看出,Rust 的宏是有基本的類型分類的,而不是像 C 那樣,所有參數都是沒有類型的 token。

還有一點, $crate 這個宏參數,並不在參數列表裡,所以可以推測它是用來表示某個特殊意思的參數。而從這個參數的命名上來說,它應該表示當前 crate 的名字。 vec! 當然是在 std 這個 crate 實現的。但是 std 不能假定使用這個宏的人,也把此 crate 起名叫做 std。Rust 允許用 as 關鍵字重命名一個 crate,而 $crate 理應為我們的宏適配這種命名修改。所以我們在編寫導出到 crate 外部的宏的時候,想要訪問 crate 內部的類型或者方法時,都應該使用這個參數。

第二種形式就顯得不太好閱讀,但是結合第三種形式,我們還是能猜出它的意思。第二個形式匹配 vec![a, b, c] 這樣的調用,第三個形式匹配 vec![a, b, c,] 這樣的調用。根據這種模式,我們猜測 ($($x:expr);*) 可能匹配 (a; b; c) 這種調用。

第二個形式中,參數的使用和參數定義基本上是一樣的格式(只是沒了類型定義)。所以我們猜測這個效果也就是把參數按照 a, b, c 這樣展開而已。但 box [a, b, c] 是個什麼還看不懂。根據頭上的 box_syntax ,我覺得這是一種還沒有 stable 的新的語法。

可以看出第三個形式的調用調用了第二個形式,我認為個實現沒什麼營養,可能 Rust 編譯器需要考慮一下怎麼移除這種沒必要的特性。

熱點內容
檸檬與蜂蜜泡製存儲要求 發布:2024-11-04 03:03:28 瀏覽:759
我的世界網易版怎麼找回伺服器 發布:2024-11-04 02:45:49 瀏覽:568
如何銀行卡綁定支付寶快捷支付密碼是什麼 發布:2024-11-04 02:45:38 瀏覽:585
20款裂行都有哪些配置 發布:2024-11-04 02:44:06 瀏覽:166
python中merge 發布:2024-11-04 02:44:06 瀏覽:908
騰訊通中心伺服器如何設置 發布:2024-11-04 02:42:37 瀏覽:165
androidgooglemap開發 發布:2024-11-04 02:36:37 瀏覽:89
80s緩存 發布:2024-11-04 02:34:11 瀏覽:391
java的swing教程 發布:2024-11-04 02:34:10 瀏覽:779
mysql的查詢緩存 發布:2024-11-04 02:31:53 瀏覽:366