库
假设有 library
声明:
library fuchsia.examples;
绑定代码会生成到 examples
Go 软件包中,该软件包将通过获取 FIDL 库名称的最后一个组成部分来获取。
可使用以下路径导入软件包:
import "fidl/fuchsia/examples"
常量
常量作为 const
块生成。例如,以下常量:
const BOARD_SIZE uint8 = 9;
const NAME string = "Tic-Tac-Toe";
生成为:
const (
BoardSize uint8 = 9
Name string = "Tic-Tac-Toe"
)
内置类型中概述了 FIDL 基元类型和 Go 类型之间的对应关系。
字段
本部分介绍 FIDL 工具链如何将 FIDL 类型转换为 Go 中的原生类型。这些类型可以在聚合类型中显示为成员,或显示为协议方法的参数。
内置类型
根据下表,FIDL 类型转换为 Go 类型。
FIDL 类型 | 围棋类型 |
---|---|
bool |
bool |
int8 |
int8 |
int16 |
int16 |
int32 |
int32 |
int64 |
int64 |
uint8 |
uint8 |
uint16 |
uint16 |
uint32 |
uint32 |
uint64 |
uint64 |
float32 |
float32 |
float64 |
float64 |
array<T, N> |
[N]T |
vector<T>:N |
[]T |
vector<T>:N? |
*[]T |
string |
string |
string:optional |
*string |
server_end:P |
生成的服务器端类型 PInterfaceRequest ,请参阅协议 |
client_end:P |
生成的客户端端类型 PInterface ,请参阅协议 |
zx.Handle:S ,zx.Handle:<S, optional> |
如果 Go 运行时支持,则使用等效的句柄类型(例如 zx.VMO 、zx.Channel 和 zx.Event )。否则,使用 zx.Handle |
zx.Handle ,zx.Handle:optional |
zx.Handle |
用户定义的类型
在 Go 中,用户定义的类型(位、枚举、常量、结构体、联合或表)使用生成的类型来引用(请参阅类型定义)。用户定义的类型 T
的可为 null 版本,是通过使用指向生成的类型 *T
的指针来引用的。
类型定义
请注意,在本部分中,生成的 Go 代码示例并未代表 FIDL 生成的确切代码。例如,生成的结构体可能包含无法通过反射检查的非导出字段。
块数
根据 bits 定义:
const BOARD_SIZE uint8 = 9;
const NAME string = "Tic-Tac-Toe";
FIDL 会为基础类型(如果未指定,则为 uint32
)生成一个类型别名,并为每个位成员生成常量:
type FileMode uint16
const (
FileModeRead FileMode = 1
FileModeWrite FileMode = 2
FileModeExecute FileMode = 4
FileMode_Mask FileMode = 7
)
FileMode_Mask
值是一个位掩码,其中包含 FIDL 架构中定义的每个位成员。
此外,它还为 FileMode
提供了以下方法:
func (x FileMode) String() string
:返回人类可读的位字符串。func (x FileMode) GetUnknownBits() uint64
:以uint64
的形式返回仅包含此位值中的未知成员的值。对于严格位,始终返回 0。func (x FileMode) HasUnknownBits() bool
:返回此值是否包含任何未知位。对于严格位,始终返回false
。func (x FileMode) InvertBits() FileMode
:反转所有已知位。所有未知位都设置为 false。func (x FileMode) ClearBits(mask FileMode) FileMode
:修改位字段,以便取消设置掩码中设置的所有位。func (x FileMode) HasBits(mask FileMode) bool
:验证是否已设置掩码中的所有翻转位。
用法示例:
func ExampleFileMode() {
fmt.Println(examples.FileModeRead.String())
fmt.Println(examples.FileModeWrite | examples.FileModeExecute)
// Output:
// Read
// Write|Execute
}
枚举
根据 enum 定义:
type LocationType = strict enum {
MUSEUM = 1;
AIRPORT = 2;
RESTAURANT = 3;
};
FIDL 会为基础类型(如果未指定,则为 uint32
)生成一个类型别名,并为每个枚举成员生成常量:
type LocationType uint32
const (
LocationTypeMuseum LocationType = 1
LocationTypeAirport LocationType = 2
LocationTypeRestaurant LocationType = 3
)
如果 LocationType
是弹性的,则它也将具有未知的占位符成员:
LocationType_Unknown LocationType = 0x7fffffff
如果枚举具有使用 [Unknown]
属性标记的成员,则生成的未知变量将与标记的未知成员具有相同的值。
LocationType
提供了以下方法:
func (x LocationType) IsUnknown() bool
:返回此枚举值是否未知。对于严格枚举,始终返回false
。func (x LocationType) String() string
:返回直观易懂的枚举字符串。
用法示例:
func ExampleLocationType() {
fmt.Println(examples.LocationTypeMuseum.String())
// Output: Museum
}
结构体
根据 struct 声明:
type Color = struct {
id uint32;
@allow_deprecated_struct_defaults
name string:MAX_STRING_LENGTH = "red";
};
FIDL 工具链会生成一个包含匹配字段的 Color
结构体:
type Color struct {
Id uint32
Name string
}
Go 绑定目前不支持结构体字段的默认值。
用法示例:
func ExampleColor() {
red := examples.Color{Id: 1, Name: "ruby"}
fmt.Println(red.Id)
fmt.Println(red.Name)
// Output:
// 1
// ruby
}
联合体
根据联合定义:
type JsonValue = strict union {
1: reserved;
2: int_value int32;
3: string_value string:MAX_STRING_LENGTH;
};
FIDL 会生成别名以及表示联合标记的相关常量:
type I_jsonValueTag uint64
const (
JsonValueIntValue = 2
JsonValueStringValue = 3
)
以及一个 JsonValue
结构体(其中包含标记和联合的每个变体的字段):
type JsonValue struct {
I_jsonValueTag
IntValue int32
StringValue string
}
JsonValue
提供了以下方法:
func (_m *JsonValue) Which() I_jsonValueTag
:返回联合标记。func (_m *JsonValue) SetIntValue(intValue int32)
和func (_m *JsonValue) SetStringValue(stringValue string)
:将联合设置为包含特定变体,并相应地更新标记。
FIDL 工具链还会生成用于构建 JsonValue
实例的工厂函数:
func JsonValueWithIntValue(intValue int32) JsonValue
func JsonValueWithStringValue(stringValue string) JsonValue
用法示例:
func ExampleJsonValue() {
val := examples.JsonValueWithStringValue("hi")
fmt.Println(val.Which() == examples.JsonValueStringValue)
fmt.Println(val.StringValue)
val.SetIntValue(1)
fmt.Println(val.Which() == examples.JsonValueIntValue)
fmt.Println(val.IntValue)
// Output:
// true
// hi
// true
// 1
}
灵活联合和未知变体
灵活联合在生成的标记类中有一个额外的变体:
const (
JsonValue_unknownData = 0
// other tags omitted...
)
当包含具有未知变体的联合体的 FIDL 消息被解码到 JsonValue
中时,.Which()
将返回 JsonValue_unknownData
。
对具有未知变体的并集进行编码,将未知数据和原始序数重新写入线上。
对未知变体进行解码时,严格并集会失败。 在解码具有句柄的未知变体时,属于值类型的灵活并集会失败。
表格
根据以下表定义:
type User = table {
1: reserved;
2: age uint8;
3: name string:MAX_STRING_LENGTH;
};
FIDL 工具链会生成一个 User
结构体,其中包含每个字段的在线状态字段:
type User struct {
Age uint8
AgePresent bool
Name string
NamePresent bool
}
User
提供了以下方法:
func (u *User) HasAge() bool
和func (u *User) HasName() bool
:检查是否存在字段。func (u *User) SetAge(age uint8)
和func (u *User) SetName(name string)
:字段 setter。func (u *User) GetAge() uint8
和func (u *User) GetName() string
:字段 getter。func (u *User) GetAgeWithDefault(_default uint8) uint8
和func (u *User) GetNameWithDefault(_default string) string
:如果不存在,则返回指定默认值的字段 getter。func (u *User) ClearAge()
和func (u *User) ClearName()
:清除字段的存在。func (u *User) HasUnknownData() bool
:检查是否存在任何未知字段。func (u *User) GetUnknownData() map[uint64]fidl.UnknownData
:返回从序数到字节的映射,以及任何未知字段的句柄。句柄列表按遍历顺序返回,如果表是值类型,则保证为空。
用法示例:
func ExampleUser() {
var user examples.User
fmt.Println(user.HasAge(), user.HasName())
user.SetAge(30)
user.SetName("John")
fmt.Println(user.GetAge(), user.GetName())
user.ClearAge()
user.ClearName()
fmt.Println(user.HasAge(), user.HasName())
fmt.Println(user.GetNameWithDefault("Unknown"))
// Output:
// false false
// 30 John
// false false
// Unknown
}
内嵌布局
生成的 Go 代码会将 fidlc
预留的名称用于内嵌布局。
协议
根据 protocol:
closed protocol TicTacToe {
strict StartGame(struct {
start_first bool;
});
strict MakeMove(struct {
row uint8;
col uint8;
}) -> (struct {
success bool;
new_state box<GameState>;
});
strict -> OnOpponentMove(struct {
new_state GameState;
});
};
FIDL 会生成一个 TicTacToeWithCtx
接口,客户端在向服务器代理调用时使用它,并由服务器使用该接口来实现协议:
type TicTacToeWithCtx interface {
StartGame(ctx_ fidl.Context, startFirst bool) error
MakeMove(ctx_ fidl.Context, row uint8, col uint8) (bool, *GameState, error)
}
每个方法都将 Context
作为第一个参数,后跟请求参数。触发和忘记方法返回 error
,双向方法返回响应参数,后跟 error
。
与 TicTacToe
协议交互的入口点具有以下函数:
func NewTicTacToeWithCtxInterfaceRequest() (TicTacToeWithCtxInterfaceRequest, *TicTacToeWithCtxInterface, error)
此函数会创建一个通道,并返回一个绑定到该通道一端的 TicTacToeWithCtxInterfaceRequest
(表示服务器端),以及一个绑定到另一端的 TicTacToeWithCtxInterface
(表示客户端)。如需了解这些内容,请参阅客户端和服务器部分。
客户端
用于通过 TicTacToe
协议进行通信的通道的客户端是 TicTacToeWithCtxInterface
。它实现了协议中所述的 TicTacToeWithCtx
接口以及用于处理事件的方法。请注意,在此实现中,双向方法调用是同步的,并且会在收到响应之前一直阻塞。
您可以在 //examples/fidl/go/client 中找到 Go FIDL 客户端的示例。
服务器
为此 FIDL 协议实现服务器时,需要提供 TicTacToeWithCtx
接口的具体实现。
这些绑定会生成一个 TicTacToeWithCtxInterfaceRequest
类型,用于表示通过 TicTacToe
协议进行通信的通道的服务器端。它提供了以下方法:
func (c EchoWithCtxInterfaceRequest) ToChannel() zx.Channel
:将接口请求转换回非类型化通道。
您可以在 //examples/fidl/go/server 中找到 Go FIDL 服务器的示例。
事件
客户端
TicTacToeWithCtxInterface
提供了处理事件的方法:
func (p *TicTacToeWithCtxInterface) ExpectOnOpponentMove(ctx_ fidl.Context) (GameState, error)
:OnOppponentMove
的事件处理脚本,它接受一个Context
并返回事件参数。
调用任何事件处理脚本方法时,系统都会读取下一个缓冲事件或块,直到接收到下一个缓冲事件或块。调用方应及时排空事件缓冲区,以免 FIDL 绑定中出现无限缓冲。如果下一个事件与调用的方法匹配,则返回其参数。否则,系统会返回错误。客户端需确保所接收事件的顺序与所处理事件的顺序一致。
服务器
服务器可以使用 TicTacToeEventProxy
发送事件,为协议中的每个事件提供方法:
func (p *TicTacToeEventProxy) OnOpponentMove(newState GameState) error
:发送OnOpponentMove
事件。
创建 TicTacToeEventProxy
需要访问客户端的通道。Go 服务器示例展示了如何在服务器端获取 EventProxy
。
成果
Go 绑定对具有错误类型的方法没有任何特殊处理。
假设该方法具有错误类型:
protocol TicTacToe {
MakeMove(struct {
row uint8;
col uint8;
}) -> (struct {
new_state GameState;
}) error MoveError;
};
TicTacToeWithCtx
接口上 MakeMove
的方法签名为:
MakeMove(ctx_ fidl.Context, row uint8, col uint8) (TicTacToeMakeMoveResult, error)
TicTacToeMakeMoveResult
是作为具有以下两个变体的并集生成的:Err
(MoveError
)和 Response
(TicTacToeMakeMoveResponse
)。
TicTacToeMakeMoveResponse
会以结构体的形式生成,其字段与成功响应的参数相对应。在本例中,它包含一个类型为 GameState
的 NewState
字段。
协议构成
FIDL 没有继承的概念,并会生成上述所有组合协议的完整代码。换句话说,
protocol A {
Foo();
};
protocol B {
compose A;
Bar();
};
提供的 API 与为以下内容生成的代码相同:
protocol A {
Foo();
};
protocol B {
Foo();
Bar();
};
除了方法序数外,生成的代码完全相同。
协议和方法属性
过渡风格
为了在 Go 中支持 @transitional
属性,FIDL 会生成一个 TicTacToeWithCtxTransitionalBase
类型,为标记为 @transitional
的每个方法提供默认实现。嵌入 TicTacToeWithCtxTransitionalBase
的服务器实现将继续构建新的过渡方法。
可检测到
标记为 @discoverable
时,生成的 InterfaceRequest
类型(在此示例中为 TicTacToeWithCtxInterfaceRequest
)会实现 fidl.ServiceRequest
,从而允许在服务发现中使用服务器端。
此外,FIDL 还会生成包含协议名称的 TicTacToeName
常量。