| 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
 
- 非 null 的 string、string:N- string:N应将预留但未使用的内存清零。
 
不支持的类型
- array<T>:N- 设为零
 
- 非 null 类型:vector<T>、vector<T>:N- 设为零
 
- 可为 null 的类型:string?、string:N?、vector<T>?、vector<T>:N?- 设为 null
 
- 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 或线格格式。
缺点、替代方案和未知情况
我们尚未评估在所有语言绑定中实现此功能是否会很简单。
在先技术和参考文档
协议缓冲区、平面缓冲区提供默认值。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
}