本文件列出在 Fuchsia 原始碼樹狀結構中編寫 Rust 時應遵循的慣例。這些慣例包含最佳做法、專案偏好以及一些做法,目的是確保一致性。
規範
命名
外殼符合 Rust 慣用語
請參閱 C-CASE。
臨時轉換遵循 as_
、to_
和 into_
慣例
詳情請參閱 C-CONV。
getter 名稱遵循 Rust 慣例
除了少數例外狀況,get_
前置字串不會用於 Rust 程式碼中的 getter。
詳情請參閱 C-GETTER。
產生疊代器的集合方法遵循 iter
、iter_mut
和 into_iter
請參閱 C-ITER。
Iterator 類型名稱與產生變數的方法相符
請參閱 C-ITER-TY。
名稱使用一致的字詞順序
請參閱 C-WORD-ORDER。
互通性
積極實作共同特徵的型別
Copy
、Clone
、Eq
、PartialEq
、Ord
、PartialOrd
、Hash
、Debug
、Display
、Default
應在適當情況下全部導入。
請參閱 C-Common-TRAITS 瞭解詳情。
轉換使用以下標準特徵:From
、AsRef
、AsMut
請參閱 C-CONV-TRAITS。
集合實作 FromIterator
和 Extend
詳情請參閱 C-COLLECT。
資料結構實作 Serde 的 Serialize
、Deserialize
詳情請參閱 C-SERDE。
類型包括 Send
和 Sync
請參閱「C-SEND-SYNC」。
錯誤類型有意義且行為良好
請參閱 C-GOOD-ERR。
二進位數字類型提供 Hex
、Octal
和 Binary
格式
請參閱 C-NUM-FMT。
一般讀取器/寫入器函式會根據值取得 R: Read
和 W: Write
請參閱 C-RW-VALUE。
巨集
輸入語法可以代表輸出內容
請參閱 C-EVOCATIVE。
巨集適合搭配屬性使用
請參閱 C-MACRO-ATTR。
項目巨集可在任何允許項目的位置運作
請參閱 C-ANYWHERE。
項目巨集支援瀏覽權限指定碼
請參閱 C-MACRO-VIS。
類型片段很靈活
詳情請參閱 C-MACRO-TY。
說明文件
Crate 層級的文件內容完整且附上範例
請參閱 C-CRATE-DOC。
所有項目都有 rustdoc 範例
詳情請參閱 C-EXAMPLE。
範例使用 ?
,而非 try!
,而非 unwrap
請參閱 C-question-MARK。
函式文件包含錯誤、恐慌和安全考量
請參閱 C-FAILURE。
淺顯版包含相關內容的超連結
詳情請參閱 C-LINK。
Rustdoc 不會顯示不實用的實作詳細資料
詳情請參閱 C-HIDDEN。
每個 unsafe
區塊都有相關的理由
要求提供安全性理由時,應先使用 // SAFETY:
,並說明為何不安全區塊發出聲音。
正確做法
// SAFETY: <why this unsafe operation's safety requirements are met>
錯誤做法
// Safety: <...>
// [SAFETY] <...>
// <...>
// SAFETY: Trust me.
使用不安全的程式碼,應說明為何必須使用不安全的區塊,以及該程式碼所含程式碼的 一個方塊就是聲音如果有安全替代方案,但可能不適合使用,那麼 也為什麼必須另外註明
正確做法
// SAFETY: The `bytes` returned from our string builder are guaranteed to be
// valid UTF-8. We used to call `from_utf8`, but this caused performance issues
// with large inputs.
let s = unsafe { String::from_utf8_unchecked(bytes) };
錯誤做法
// SAFETY: We shouldn't have to validate `bytes`, and the safe version is slow.
let s = unsafe { String::from_utf8_unchecked(bytes) };
理由應直接解決作業要求。總結來說 就能檢查是否符合條件
正確做法
// SAFETY: The caller has guaranteed that `ptr` is valid for reads, properly
// aligned, and points to a properly-initialized `T`.
unsafe {
let x = ptr.read();
}
正確做法
// SAFETY: The caller has guaranteed that `ptr` points to a valid `T`.
unsafe {
let x = ptr.read();
}
錯誤做法
// SAFETY: `ptr` is safe to read.
unsafe {
let x = ptr.read();
}
安全理由應說明作業原因「原因」,而不只是指出作業 左右對齊。
正確做法
const BUFFER_LEN: usize = 1024;
fn partially_init(n: usize) -> MaybeUninit<[i32; BUFFER_LEN]> {
// These asserts ensure our safety conditions are met later on
const _: () = assert!(BUFFER_LEN <= 1024);
assert!(n < BUFFER_LEN);
let mut buffer = MaybeUninit::<[i32; BUFFER_LEN]>::uninit();
let ptr = buffer.as_mut_ptr().cast::<i32>();
for i in 0..n {
// SAFETY:
// - `ptr` points to the first `i32` of `buffer`.
// - `buffer` has space for BUFFER_LEN elements and we asserted that
// `n < BUFFER_LEN`.
// - We asserted that `BUFFER_LEN <= 1024`, so `size_of::<i32>() * i`
// is at most 4096 which is less than `isize::MAX` and `usize::MAX`.
let element = unsafe { &mut *ptr.add(i) };
*element = i as i32;
}
buffer
}
錯誤做法
const BUFFER_LEN: usize = 1024;
fn partially_init(n: usize) -> MaybeUninit<[i32; BUFFER_LEN]> {
// Why are these asserts here?
const _: () = assert!(BUFFER_LEN <= 1024);
assert!(n < BUFFER_LEN);
let mut buffer = MaybeUninit::<[i32; BUFFER_LEN]>::uninit();
let ptr = buffer.as_mut_ptr().cast::<i32>();
for i in 0..n {
// SAFETY:
// - `ptr` is in bounds or one byte past the end of an allocated object.
// - `ptr + i` is also in bounds.
// - The computed offset, in bytes, doesn't overflow an `isize`.
// - The offset being in bounds does not rely on "wrapping around" the
// address space.
let element = unsafe { &mut*ptr.add(i) };
*element = i as i32;
}
buffer
}
不安全的特徵已記錄下來,不安全特徵已左右化
不安全的特徵應根據與不安全的功能相同的規範來記錄。
不安全的特徵定義應記錄安全考量 (請參閱 C-FAILURE)。
不安全的特徵導入方式應合理化 (詳情請參閱
"每個 unsafe
區塊都有對應的理由")
正確做法
/// A labeler that always returns unique labels.
///
/// # Safety
///
/// Every time `create_unique_label()` is called on the same labeler, it must
/// return a distinct `u32`.
unsafe trait UniqueLabeler {
/// Returns a new unique label.
fn create_unique_label(&mut self) -> u32;
}
struct SequentialLabeler {
next: Option<u32>,
}
// SAFETY: `create_unique_label()` will always return the next sequential label
// or panic if all available labels are exhausted.
unsafe impl UniqueLabeler for SequentialLabeler {
fn create_unique_label(&mut self) -> u32 {
if let Some(next) = self.next {
self.next = (next < u32::MAX).then(|| next + 1);
next
} else {
panic!("sequential unique labels exhausted");
}
}
}
錯誤做法
/// A labeler that always returns unique labels.
unsafe trait UniqueLabeler {
/// Returns a new unique label.
fn create_unique_label(&mut self) -> u32;
}
struct SequentialLabeler {
next: u32,
}
unsafe impl UniqueLabeler for SequentialLabeler {
fn create_unique_label(&mut self) -> u32 {
// This will have correct panicking behavior in debug builds because
// integer overflow is trapped. In a release build, this will still
// overflow but our labeler will not panic!
let result = self.next;
next += 1;
result
}
}
不安全的作業一律位於 unsafe
區塊
在 Fuchsia 中,unsafe
函式不屬於不安全的環境。不安全的作業必須一律
位於 unsafe
區塊中,即使它們位於 unsafe
函式主體中也是如此。
正確做法
unsafe fn clear_slice(ptr: *mut i32, len: usize) {
assert!(len.checked_mul(mem::size_of::<i32>()).unwrap() < isize::MAX);
// SAFETY:
// - The caller has guaranteed that `ptr` points to `len` consecutive, valid
// i32s and that the data at behind `ptr` is not simultaneously accessed
// through any other pointer.
// - We asserted that the total size of the slice is less than isize::MAX.
let slice = unsafe { slice::from_raw_parts_mut(ptr, len) };
for x in slice.iter_mut() {
*x = 0;
}
}
錯誤做法
unsafe fn clear_slice(ptr: *mut i32, len: usize) {
// We forgot to assert that the length of the slice is less than isize::MAX!
// If we justified our call to from_raw_parts_mut, we would have been much
// more likely to remember.
let slice = slice::from_raw_parts_mut(ptr, len);
for x in slice.iter_mut() {
*x = 0;
}
}
可預測性
智慧指標不會新增固有方法
詳情請參閱 C-SMART-PTR。
轉換發生在最明確相關的類型
詳情請參閱 C-CONV-SPECIFIC
具有明確接收器的函式是方法
詳情請參閱 C-METHOD。
函式不會擷取參數
詳情請參閱 C-NO-OUT。
運算子超載出現意料之外
請參閱 C-OVERLOAD。
只有智慧指標實作 Deref
和 DerefMut
請參閱 C-DEREF。
建構函式為靜態的固有方法
詳情請參閱 C-CTOR。
彈性高
函式會公開中繼結果,避免重複作業
請參閱 C-INTERMEDIATE。
呼叫端決定要複製及放置資料的位置
請參閱 C-CALLER-CONTROL。
函式會使用泛型,盡量減少對參數的假設
請參閱 C-GENERIC。
特徵若可能做為特徵物件,就可視為物件安全
詳情請參閱 C-OBJECT。
類型安全
新類型提供靜態的差異
請參閱 C-NEWTYPE。
引數會透過型別 (而非 bool
或 Option
) 傳達意義
請參閱「C-CUSTOM-TYPE」。
一組標記的類型是 bitflags
,不是列舉
詳情請參閱 C-BITFLAG。
建構工具支援建構複雜值
詳情請參閱 C-BUILDER。
可靠度
函式會驗證其引數
請參閱 C-VALIDATE。
解構函式永遠不會失敗
詳情請參閱 C-DTOR-FAIL。
可能阻擋的解構函式有替代選項
請參閱「C-DTOR-BLOCK」。
可進行偵錯
所有公開類型都能實作 Debug
詳情請參閱 C-DEBUG。
Debug
表示法並非空白
請參閱 C-DEBUG-NONEMPTY。
符合未來趨勢
密封特性可防止下游實作
詳情請參閱 C-SEALED。
結構包含私人欄位
請參閱 C-STRUCT-PRIVATE。
新類型會封裝實作詳細資料
請參閱 C-NEWTYPE-HIDE。
資料結構不會複製衍生特徵邊界
請參閱 C-STRUCT-BOUNDS。
更新規範
如要提出增補或修改要求,請開啟 CL 和副本
fuchsia-rust-api-rubric@google.com
,確認評論已送交審查。使用任何
提供意見回饋。
我們處理完意見回饋後,將造成這個檔案的任何擁有者
提案的作者無法擔任講師,並將提案移至最後
呼叫。講師會傳送電子郵件給 fuchsia-rust-api-rubric@google.com
宣布提案最後一則通話提案會開放提供意見
7 天。
在上個通話週期結束時,對於提出相關疑慮後, 上次討論或提及時,講師會在 CL 上 根據審查意見回饋和討論內容做出決定任何爭議性內容 必須充分公開討論相關問題 並且在 CL 註解中說明原因決策結果 電子郵件執行緒
如果提案通過,講師會留下 +2,作者可以 然後提交檔案
待審核的主題
您可以透過 Rust Issue Tracker 元件追蹤待處理主題。
與上游 Rust API 規範的關係
這份評分量表涵蓋大部分的 Rust API 指南,但下列條件如下: 省略官方規範:
- C-FEATURE,因為 Fuchsia 並未 目前支援 Crate 的功能。
- C-METADATA 做為 Fuchsia
不會維護內部
Cargo.toml
檔案。 - C-HTML-ROOT 為
Fuchsia 目前不會將大部分的 Rust 程式碼發布至
crates.io
。 - C-RELNOTES 最大 Fuchsia 中的 Rust 程式碼「活在 HEAD」。
- C-STABLE:與 Fuchsia 的做法相同
目前不會將大部分的 Rust 程式碼發布至
crates.io
。 - C-PERMISSIVE 和 Fuchsia 的 Rust 程式碼已通過 Fuchsia 授權。
包含下列 Fuchsia 相關規範: