另請參閱 FIDL API 評量表。
名稱
貓咪命名是件難事,
不只是節慶遊戲而已;
--- T.S. 艾略特
FIDL 中定義的名稱會用於在各目標語言中產生 ID。某些語言會為各種形式的名稱附加語意或傳統意義。舉例來說,在 Go 中,識別碼開頭字母是否大寫會控管識別碼的可見度。因此,許多語言後端會轉換媒體庫中的名稱,使其更適合目標語言。本節的命名規則旨在兼顧 FIDL 來源的可讀性、各目標語言的可用性,以及目標語言之間的一致性。
請避免使用常見的保留字,例如 goto。 語言後端會將保留字轉換為非保留的 ID,但這些轉換會降低這些語言的可用性。避免使用常見的保留字,可減少套用這些轉換的頻率。
部分 FIDL 關鍵字也是目標語言中常見的保留字 (例如 C 和 C++ 中的 struct),因此應避免使用。不過,其他 FIDL 關鍵字 (尤其是 request 和 handle) 通常具有描述性,可視情況使用。
名稱開頭或結尾不得有底線。在某些語言中,開頭或結尾底線具有語意意義 (例如,開頭底線可控制 Dart 中的可見度),在其他語言中則具有慣例意義 (例如,結尾底線通常用於 C++ 中的成員變數)。此外,FIDL 編譯器會使用開頭和結尾底線來混淆處理 ID,避免發生衝突。
使用 size 字詞命名位元組數。使用 count 這個字詞來命名其他數量 (例如結構體向量中的項目數量)。
案件定義
有時候,決定如何劃分 ID 中的字詞不只一種方式。我們的風格如下:
- 先以美式英文輸入原始片語 (例如 "Non-Null HTTP Client")
- 移除所有標點符號。("Non Null HTTP Client")
- 將所有內容設為小寫 (「non null http client」)
- 請根據適用於指定 ID 的樣式,執行下列任一操作:
- 將空格替換為底線 (「_」),以使用小寫蛇形命名法 (
non_null_http_client)。 - 將空格換成底線,並將字元改為大寫,即為大寫蛇形命名法 (
NON_NULL_HTTP_CLIENT)。 - 將每個字詞的第一個字母大寫,並將所有字詞合併為大駝峰式命名法 (
NonNullHttpClient)。
- 將空格替換為底線 (「_」),以使用小寫蛇形命名法 (
用量
下表列出大小寫用法與元素的對應關係:
| 元素 | 編織密度 | 範例 |
|---|---|---|
bits |
大寫駝峰式大小寫 | InfoFeatures |
| 位元欄位成員 | 大寫蛇形命名法 | WLAN_SNOOP |
const |
大寫蛇形命名法 | MAX_NAMES |
alias |
大寫駝峰式大小寫 | DeviceId |
protocol |
大寫駝峰式大小寫 | AudioRenderer |
| 通訊協定方法參數 | 小寫蛇形命名法 | enable_powersave |
| 通訊協定方法 | 大寫駝峰式大小寫 | GetBatteryStatus |
struct |
大寫駝峰式大小寫 | KeyboardEvent |
| 結構體成員 | 小寫蛇形命名法 | child_pid |
table |
大寫駝峰式大小寫 | ComponentDecl |
| 資料表成員 | 小寫蛇形命名法 | num_rx |
union |
大寫駝峰式大小寫 | BufferFormat |
| 工會成員 | 小寫蛇形命名法 | vax_primary |
enum |
大寫駝峰式大小寫 | PixelFormat |
| 列舉成員 | 大寫蛇形命名法 | RGB_888 |
程式庫
程式庫名稱是以半形句號分隔的 ID 清單。最後一個以外的程式庫名稱部分也稱為命名空間。名稱的每個元件都必須是小寫,且符合下列規則運算式:[a-z][a-z0-9]*。
我們使用這些限制性規則,是因為不同目標語言對命名空間、程式庫或套件的合格方式有不同的限制。我們選取了保守的最小公分母,以便 FIDL 能與目前的目標語言集和潛在的未來目標語言搭配運作。
ID 名稱:偏好使用有意義的職務角色
建議使用功能名稱 (例如 fuchsia.media) 超過產品或代碼名稱
(例如fuchsia.amber 或 fuchsia.scenic)。如果產品在 Fuchsia 以外有外部存在,且通訊協定專屬於該產品,則產品名稱就適用。舉例來說,fuchsia.cobalt 是比 fuchsia.metrics 更適合 Cobalt 介面通訊協定的名稱,因為其他指標實作 (例如 Firebase) 都不太可能實作相同的通訊協定。
識別碼名稱應與參與者扮演的特定角色相關,請避免將存取權控管編碼至名稱中。以角色為依據的名稱具有描述性,且不會像以存取權控管為依據的名稱一樣快速過時,因為存取權控管會規定外部定義的關係,而這類關係會隨著平台演進而變更。舉例來說,如果 API 涉及 FocusChain 物件,適當的名稱應為 fuchsia.ui.focus,而非 fuchsia.ui.privileged;如果我們決定讓 FocusChain 物件更廣為人知,則 fuchsia.ui.focus 並非有問題的名稱。請避免使用下列範例字詞:
constrainedlimitedoemprivateprivilegedprotectedspecialvendor
識別項名稱應有意義,請避免使用無意義的名稱。如果 fuchsia.foo.bar 和 fuchsia.foo.baz 共用許多概念,而您希望將這些概念分解到個別程式庫中,請考慮在 fuchsia.foo 中定義這些概念,而不是在 fuchsia.foo.common 中定義。請避免使用下列範例字詞:
commonserviceutilbasef<letter>lzx<word>
頂層
請避免重複使用資料庫名稱中的名稱。舉例來說,在 fuchsia.process 程式庫中,啟動程序的通訊協定應命名為 Launcher,而非 ProcessLauncher,因為名稱 process 已出現在程式庫名稱中。在所有目標語言中,頂層名稱都會以某種方式依程式庫名稱設定範圍。
原始別名
原始別名不得重複使用封閉程式庫中的名稱。在所有目標語言中,原始別名都會替換為基礎原始型別,因此不會造成名稱衝突。
alias vaddr = uint64;
常數
常數名稱不得重複使用封閉程式庫中的名稱。在所有目標語言中,常數名稱都會以封閉程式庫為範圍。
描述下限和上限的常數應分別使用 MIN_ 和 MAX_ 前置字元。
const MAX_NAMES uint64 = 32;
通訊協定
通訊協定是以 protocol 關鍵字指定。
通訊協定必須是名詞片語。
通常會使用表示動作的名詞來命名通訊協定。舉例來說,AudioRenderer 是名詞,表示通訊協定與音訊算繪相關。同樣地,Launcher 是名詞,表示通訊協定與啟動某項事物有關。通訊協定也可以是被動名詞,特別是與實作所保留的某些狀態相關時。舉例來說,Directory 是名詞,表示通訊協定用於與實作項目持有的目錄互動。
通訊協定可使用物件導向設計模式命名。舉例來說,fuchsia.fonts.Provider 使用 provider 後置字元,表示通訊協定提供字型 (而非代表字型本身)。同樣地,fuchsia.tracing.Controller 使用 controller 後置字元,表示通訊協定控制追蹤系統 (而非代表追蹤本身)。
名稱 Manager 可做為範圍廣泛的通訊協定最後手段。例如:fuchsia.power.Manager。不過請注意,「管理員」通訊協定往往會吸引大量鬆散相關的功能,這些功能或許更適合納入多個通訊協定。
通訊協定不得包含 service. 名稱。所有通訊協定都會定義服務。
這個字詞沒有意義。舉例來說,fuchsia.tts.TtsService 有兩項違規行為。首先,Tts 前置字串與程式庫名稱重複。其次,禁止使用「Service」後置字元。
露骨內容「open/ajar/closed」修飾符
對於通訊協定,請務必指定 open、ajar 或 closed,而非依賴預設值。也就是說,一律優先使用 open protocol Foo {
...,而非僅使用 protocol Foo { ...。
方法
方法必須是動詞片語。
舉例來說,GetBatteryStatus 和 CreateSession 是動詞片語,表示方法執行的動作。
發生事件時呼叫的 listener 或 observer 通訊協定方法應以 On 為前置字串,並以過去式描述發生的事件。舉例來說,ViewContainerListener 通訊協定有名為 OnChildAttached 的方法。
活動
同樣地,事件 (即伺服器傳送給用戶端的未經要求訊息) 應以 On 為前置字元,並以過去式描述發生的事件。
舉例來說,AudioCapturer 通訊協定有名為 OnPacketCaptured 的事件。
單一方法通訊協定
單一方法通訊協定的方法應為通訊協定名詞片語的動詞片語,例如 Loader.Load、Getter.Get、Uploader.Upload。如果是合格的名詞片語,例如 JobCreator 或 ProcessStopper,則應使用不合格的動詞片語,即 JobCreator.Create 或 ProcessStopper.Stop。
如果通訊協定是單一方法,但打算隨著時間演變成多種方法,則不一定需要遵循這項命名慣例。也就是說,如果通訊協定有已知的擴充功能,但建議的命名方式不適用,則可能較適合選擇其他名稱。如有疑問,建議優先採用預設建議。
因為取代通訊協定比演進通訊協定更困難,如果 API 從未打算演進,但最終發現需要改用多種方法的通訊協定,建議您新增方法來演進現有通訊協定,並視需要重新命名現有方法。
露骨內容「strict/flexible」修飾符
對於方法和事件,請一律指定 strict 或 flexible,而非依預設值。也就是說,請一律優先使用 flexible Foo();,而非僅使用 Foo()。
結構體、聯集和資料表
結構體、聯集和表格必須是名詞片語。
舉例來說,Point 是定義空間中位置的結構,而 KeyboardEvent 則是定義鍵盤相關事件的結構。
結構體、聯集和資料表成員
實用時,請偏好使用單一字詞的結構體、聯集和資料表成員名稱 (單一字詞名稱在目標語言中會更一致地呈現)。不過,如果單一字詞會造成模稜兩可或令人困惑的情況,請放心使用多個字詞。
成員名稱不得重複使用封閉型別 (或程式庫) 中的名稱,除非成員名稱在沒有封閉型別名稱的情況下會造成混淆。舉例來說,如果類型為 KeyboardEvent 的成員包含事件傳送時間,則應命名為 time,而非 event_time,因為名稱 event 已出現在封閉型別的名稱中。在所有目標語言中,成員名稱都會以其封閉型別為範圍。
不過,如果類型 DeviceToRoom 會將智慧型裝置與所在房間建立關聯,則可能需要有成員 device_id 和 room_name,因為 id 和 name 不明確。這兩者都可能指裝置或房間。
列舉
列舉必須是名詞片語。
舉例來說,PixelFormat 是列舉,定義色彩在圖片中如何編碼為位元。
列舉成員
列舉成員名稱不得與封閉型別 (或程式庫) 中的名稱重複。
舉例來說,PixelFormat 列舉的成員應命名為 ARGB,而非 PIXEL_FORMAT_ARGB,因為名稱 PIXEL_FORMAT 已出現在封閉型別的名稱中。在所有目標語言中,列舉成員名稱都會以封閉型別為範圍。
Bitfields
位元欄位必須是名詞片語。
舉例來說,InfoFeatures 是位元欄位,用於指出乙太網路介面上的功能。
位元欄位成員
位元欄位成員不得重複使用封閉型別 (或程式庫) 的名稱。
舉例來說,InfoFeatures 位元欄位的成員應命名為 WLAN,而非 INFO_FEATURES_WLAN,因為 INFO_FEATURES 名稱已出現在封閉型別的名稱中。在所有目標語言中,位元欄位成員名稱都會以封閉型別為範圍。
類型
露骨內容「strict/flexible」修飾符
對於接受 strict/flexible 修飾符的類型 (bits、enum 和 union),請務必指定這類修飾符,而非依賴預設值。也就是說,一律優先使用 flexible bits ...,而非僅使用 bits ...。
機構
語法
- 使用 4 個空格的縮排。
- 請勿使用分頁。
- 請勿加入結尾空白字元。
- 以空白行 (兩個連續的換行字元) 將
bits、enum、protocol、struct、table和union建構函式的宣告與其他宣告分開。 - 檔案結尾必須只有一個換行字元。
留言
註解使用 /// (三個正斜線)。程式庫中的註解也會顯示在產生的程式碼中,方便您根據程式庫編寫程式碼時進行開發。我們稱之為「流向」目標語言。
將註解放在所描述內容的上方。除非是下列情況,否則請使用大小寫正確的完整句子,並加上句號。除非註解過長而無法避免 (例如網址很長),否則請將註解寬度限制在 80 個字元內。
請以 Markdown 撰寫註解。我們的 Markdown 採用 CommonMark 規格。部分工具可能會使用其他 Markdown 標準算繪輸出內容;如果您的工具未使用 CommonMark,建議開發人員編寫與 CommonMark 和工具相容的 Markdown。FIDL 元素的參照一律應以程式碼字型呈現。
有附加註解的任何 FIDL 元素都是已記錄的實體。註解中首次提及任何已記錄的實體時,應使用完整名稱,格式為 [`<library>/<top level declaration>.<member>`] (例如 [`fuchsia.io/Node.clone`])。如果工具支援,這份表單可能會產生超連結。後續參照該記錄實體時,可以使用縮寫版本,但縮寫版本必須明確 (例如 clone)。不含方括號的表單不會產生超連結。
描述變數、欄位或型別的文件註解第一部分應為名詞片語,簡要說明所記錄實體的預期用途,包括無法從名稱和型別推斷的資訊。說明應以句號結尾。說明不應重述記錄實體的名稱,或其特定類型的 FIDL 語言元素 (例如 struct 或 protocol)。
/// A representation of violins displayed on the screen.
type Widget = struct {
/// A monotonically increasing id, uniquely identifying the widget.
id uint64;
/// Location of the top left corner of the widget.
location Point;
};
以下是幾個不應採取的做法:
/// BAD: Widget is a representation of violins displayed on the screen.
/// BAD: struct Widget is a representation of violins displayed on the screen.
附加至通訊協定方法的文件註解第一部分,應簡要說明該方法的行為,並以動詞開頭,包括無法從名稱和型別推斷的資訊。動詞應以現在式撰寫,與第三人稱單數代名詞一致,並使用直陳語氣 (這實際上表示您應假設動詞前有「it」一字,且您正在陳述事實)。詞組結尾應加上句點。
要求和回應參數應內嵌在對應的結構體或表格中。
如果通訊協定傳回錯誤值,應在「錯誤」小節中記錄:
## Error
Description of the error value.
完整範例:
/// An abstract representation of a [`fuchsia.io/Node`] whose layout is flat.
protocol File {
compose Node;
/// Acquires a [`fuchsia.mem/Buffer`] representing this file, if
/// there is one, with the requested access rights.
///
/// ## Rights
///
/// This method requires the following rights:
///
/// * [`fuchsia.io/OPEN_RIGHT_WRITABLE`] if `flags` includes
/// [`fuchsia.io/VMO_FLAG_WRITE`].
/// * [`fuchsia.io/OPEN_RIGHT_READABLE`] if `flags` includes
/// [`fuchsia.io/VMO_FLAG_READ`] or [`fuchsia.io/VMO_FLAG_EXEC`].
///
/// ## Error
///
/// Returns ZX_ERR_INVALID_ARGS if `flags` contains an invalid VMO flag.
/// Returns ZX_ERR_NOT_FOUND if the requested buffer does not exist.
///
/// * see [`fuchsia.mem/Buffer`]
/// [`fuchsia.mem/Buffer`]:
/// https://fuchsia.googlesource.com/fuchsia/+/HEAD/sdk/fidl/fuchsia.mem/buffer.fidl
GetBuffer(struct {
/// A bit field composing any of `VMO_FLAG_READ`, `VMO_FLAG_WRITE`, or
/// `VMO_FLAG_EXEC`.
flags uint32;
}) -> (resource struct {
/// The requested `fuchsia.mem/Buffer`.
buffer box<fuchsia.mem.Buffer>;
}) error zx.Status;
};
由某些外部事實來源定義的型別或值應加上註解,並參照外部事物。舉例來說,您可以參照說明設定結構的 Wi-Fi 規格。同樣地,如果結構體必須符合 C 標頭中定義的 ABI,請參照 C 標頭。
如要進一步瞭解註解應包含的內容,請參閱 API 說明文件評分標準。
參照 FIDL 通訊協定或通訊協定方法
註解中提及 FIDL 通訊協定或其方法時,應遵循下列模式:
/// See fuchsia.library/ProtocolName.Method for more information.
在與註解相同的程式庫中參照通訊協定時,可以省略程式庫名稱:ProtocolName.Method。
同樣地,如果註解參照的通訊協定與註解本身位於同一通訊協定,則可省略程式庫名稱和通訊協定名稱:Method。
程式庫總覽
您可以在 library 陳述式中提供程式庫總覽,做為說明文件註解。「library」陳述式會啟動 FIDL 檔案。例如:
/// Library containing example FIDL used throughout the Fuchsia documentation.
library fuchsia.examples.docs;
程式庫總覽應提供一般說明文件,定義程式庫。他們也可能會詳細介紹各種訊息、定義的通訊協定,以及如何一併使用訊息和通訊協定。
程式庫可以分成多個 FIDL 檔案,但只能有一個程式庫總覽。以下是程式庫總覽的建議:
- 如果概覽很短,且程式庫只包含單一檔案,您可以將概覽放在程式庫檔案頂端的
library陳述式中。 - 如果程式庫包含多個檔案,請建立獨立的
overview.fidl檔案來記錄程式庫。「overview.fidl」檔案不應包含任何宣告、型別別名或通訊協定定義。
非流動式註解
如果註解是給程式庫作者看的,請使用較簡單的註解 // (兩個斜線),這類註解不會傳遞至目標語言。
決定哪些應為一般 /// 註解,哪些應為非流通註解時,請注意下列事項。
一般留言:
- 參數、引數、函式說明
- 使用須知
非流動註解:
- 內部「待辦事項」留言
- 著作權聲明
- 導入作業詳細資料
兩種樣式的註解可以合併使用:
/// A widget displaying violins on the screen.
// TODO -- widgets should use UUIDs instead of sequential ids
type ViolinWidget = struct {
/// A monotonically increasing id, uniquely identifying the widget.
id uint64;
/// Location of the top left corner of the widget.
location Point;
};
檔案
程式庫包含一或多個檔案。檔案會儲存在目錄階層中,並遵循下列慣例:
fidl/<library>/[<dir>/]*<file>.fidl
<library> 目錄的命名方式是使用以半形句號分隔的 FIDL 程式庫名稱。<dir> 子目錄為選用項目,通常不會用於檔案少於十幾個的程式庫。這個目錄結構與 Fuchsia SDK 中 FIDL 檔案的納入方式相符。
將程式庫劃分為多個檔案,對程式庫的消費者沒有技術影響。無論宣告出現在哪個檔案中,程式庫中的宣告 (包括通訊協定) 都可以互相參照,也可以參照自身。將程式庫分成多個檔案,盡可能提高可讀性。
- 建議使用程式庫中檔案的 DAG 依附元件圖表。
- 建議將相互參照的定義文字彼此靠近,最好是在同一個檔案中。
- 如果是複雜的程式庫,建議在葉片檔案中定義純資料型別或常數,並在主幹檔案中定義參照這些型別的通訊協定。