RFC-0022:说明:结构体成员的默认值

RFC-0022:说明:结构体成员的默认值
状态已接受
领域
  • FIDL
说明

FIDL 结构体成员可以具有默认值。目前,对默认设置的支持已部分实现(请参见下一部分),该方案旨在阐明默认设置的行为方式。

作者
提交日期(年-月-日)2018-07-17
审核日期(年-月-日)2018-09-27

摘要

FIDL 结构体成员可以具有默认值。 目前,对默认值的支持已部分实现(请参阅下文), 该方案旨在阐明默认设置的行为方式。

设计初衷

  1. 它可以确保语言绑定的规律性, 使用方式不一致或意外使用
  2. 避免了手动进行逐个成员初始化的麻烦, 而语言需要显式初始化,

非动机包括:

  • 以传输格式保存字节

不是为了节省传输格式的字节或节省处理工作的动机 编码或解码。

今天的实现

默认值可以在结构体成员上以 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,其中阐明了默认值的语义, 有关绑定的要求和要求

支持的类型

  • 基元类型: <ph type="x-smartling-placeholder">
      </ph>
    • boolint8int16int32int64uint8uint16uint32 uint64float32float64
  • stringstring:N 不可为 null <ph type="x-smartling-placeholder">
      </ph>
    • string:N 应将预留而未使用的内存清零。

不支持的类型

  • array<T>:N
    • 设置为零
  • 不可为 null 的类型:vector<T>vector<T>:N <ph type="x-smartling-placeholder">
      </ph>
    • 设置为零
  • 可为 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
}