RFC-0022:說明:結構體成員的預設值 | |
---|---|
狀態 | 已接受 |
區域 |
|
說明 | FIDL 結構體成員可能會有預設值。目前,系統僅部分支援預設值 (請參閱下文),而這項提案旨在說明預設值應如何運作。 |
作者 | |
提交日期 (年-月-日) | 2018-07-17 |
審查日期 (年-月-日) | 2018-09-27 |
摘要
FIDL 結構體成員可能會有預設值。目前,系統僅部分支援預設值 (請參閱下文),而這項提案旨在說明預設值應如何運作。
提振精神
- 它可在語言繫結中提供規則性,提供不一致或意外使用情況的防護機制,
- 當語言要求明確的初始化時,可免除繁瑣的手動逐一成員初始化作業,
非動機包括:
- 以線格格式儲存位元組
這不是為了在執行編碼或解碼時,以線路格式儲存位元組或節省處理功率。
今天的實作
您可以使用 FIDL 語言在結構體成員上表示預設值:
- (+) 支援數值常值、布林常值和字串常值。
- (-)
fidlc
不會為結構體成員的字面值可指派性提供類型檢查。您可以將字串常值「hello」指派給布林值、負數指派給 uint,或超出邊界值指派給 int16。 - (-) 語言繫結支援功能不一致,目前僅支援 C++ 和 Dart 繫結。不支援 Go、C 或 Rust。
例如 (取自 //zircon/system/host/fidl/examples/types.test.fidl):
struct default_values {
bool b1 = true;
bool b2 = false;
int8 i8 = -23;
int16 i16 = 34;
int32 i32 = -34595;
int64 i64 = 3948038;
uint8 u8 = 0;
uint16 u16 = 348;
uint32 u32 = 9038;
uint64 u64 = 19835;
float32 f32 = 1.30;
float64 f64 = 0.0000054;
string s = "hello";
};
設計
預設值可在結構體成員上定義。預設值會顯示在欄位定義的結尾,並採用類似 C 的 = {value}
模式。
語法
// cat.fidl
enum CatAction : int8 {
SIT = -10;
WALK = 0;
SNEAK = 2;
};
struct Location {
uint8 pos_x = 10; // Position X
uint8 pos_y; // Position Y. Default unspecified. Fall-back to 0
float32 pos_z = 3.14; // Position Z.
float32 pos_t; // Default unspecified. Fall-back to 0.0
};
struct Cat {
string name; // Automatic default to empty string
CatAction action = CatAction::SNEAK;
Location loc;
};
語義學
請參閱 RFC-006,其中說明瞭預設值的語意,以及繫結的相關規定。
支援的類型
- 原始類型:
bool
、int8
、int16
、int32
、int64
、uint8
、uint16
、uint32
、uint64
、float32
、float64
- 非空值
string
、string:N
string:N
應將未使用的預留記憶體設為零。
不支援的類型
array<T>:N
- 設為零
- 非空值類型:
vector<T>
、vector<T>:N
- 設為零
- 可為空值的類型:
string?
、string:N?
、vector<T>?
、vector<T>:N?
- 設為空值
handle
struct
- 雖然
struct
中的每個成員可能都有預設值,但struct
本身並沒有預設值。
- 雖然
union
- 為避免任何衝突,系統會忽略
union
成員的任何預設值,或union
的任何深度的子結構。
- 為避免任何衝突,系統會忽略
預設值的細微差異
重點在於值本身,而非指派值的方式。這至少暗示了兩件事:
- 無論您是否使用預設值,都沒有差異,因為您感興趣的參數已透過其他機制明確指派。
- 在繫結或解繫結時,沒有額外的 (透明) 邏輯層來指派值。
實作
以下是 C、Rust 和 Go 繫結的實作想法示例
// in FIDL "default.fidl"
struct Location {
uint8 pos_x = 10;
uint8 pos_y = 20;
uint8 pos_x; // Should be set to "zero" according to above.
};
// C binding "defaults/fidl.h"
typedef struct _Location_raw {
uint8_t pos_x;
uint8_t pos_y;
uint8_t pos_z
} Location;
Location Location_default = { 10, 20, 0 }; // Or in the source file.
// May be used for memcmp,
memcpy, etc.
#define Location(my_instance) Location my_instance = Location_default;
// C code "example.c"
#include <fidl.h>
void showme(Location loc) {
printf("(%u, %u, %u)\n", loc.pos_x, loc.pos_y, loc.pos_z);
}
int main() {
Location(alpha);
Location beta;
Location gamma = Location_default;
showme(alpha); showme(beta); showme(gamma);
return 0;
}
// Rust binding
struct Location {
pos_x: u8,
pos_y: u8,
pos_z: u8,
}
impl std::default::Default for Location {
fn default() -> Self { Self { pos_x: 10, pos_y: 20, pos_z: 0 } }
}
// Go binding, using export control
type location struct {
pos_x uint8
pos_y uint8
pos_z uint8
}
Func NewLocation() location {
loc := location{}
loc.pos_x = 10
loc.pos_y = 20
// loc.pos_z = 0 Maybe omitted.
return loc
}
成效
不適用
安全性
不適用
測試
不適用
回溯相容性
這項變更會讓 FIDL 檔案來源不具回溯相容性。不需要變更 ABI 或線路格式。
缺點、替代方案和未知事項
我們不會評估在所有語言繫結中實作這項功能是否簡單明瞭。
既有技術與參考資料
通訊協定緩衝區:Flat 緩衝區會提供預設值。Golang 有「零值」概念,如果宣告的變數沒有明確的初始值,系統會明確將其初始化為零。
開放原始碼方法:
// From https://github.com/creasty/defaults
type Sample struct {
Name string `default:"John Smith"`
Age int `default:"27"`
Gender Gender `default:"m"`
Slice []string `default:"[]"`
SliceByJSON []int `default:"[1, 2, 3]"` // Supports JSON format
Map map[string]int `default:"{}"`
MapByJSON map[string]int `default:"{\"foo\": 123}"`
Struct OtherStruct `default:"{}"`
StructPtr *OtherStruct `default:"{\"Foo\": 123}"`
NoTag OtherStruct // Recurses into a nested struct even without a tag
OptOut OtherStruct `default:"-"` // Opt-out
}