试用了下FlatBuffers,把一些东东记录一下。
FlatBuffers 官网: http://google.github.io/flatbuffers/md__go_usage.html
@H_404_6@1. 定义IDL 接口定义文件,通常命名为.fbs参考: Writing a schema
http://google.github.io/flatbuffers/md__schemas.html
@H_404_6@2. 利用flatc 解析生成语言的文件
flatc
参考: Using the schema compiler
http://google.github.io/flatbuffers/md__compiler.html
生成Go的参数:
-g : Generate Go classes. Skipped for data.
@H_404_6@3. 在Go工程中安装FlatBuffers的Go支持包,就可以在代码直接使用了.
再详细说说FlatBuffers的一些特性。先上一份.fbs的例子:
// example IDL file
namespace MyGame;
attribute "priority";
enum Color : byte { Red = 1,Green,Blue }
///union Any { Monster,Weapon,Pickup }
//union Any { Monster}
union Any { Monster,Weapon}
struct Vec3 {
x:float;
y:float;
z:float;
}
/// 注释
table Monster {
pos:Vec3;
mana:short = 150;
hp:short = 100;
name:string;
friendly:bool = false (deprecated,priority: 1);
inventory:[ubyte];
color:Color = Blue;
test:Any;
}
table Weapon {
pos:Vec3;
mana:short = 150;
}
root_type Monster;
root_type Weapon;依上面的IDL作例子来说明一下.
@H_404_6@IDL生成结果:
会在MyGame下,生成Any.go,Color.go,Monster.go,Vec3.go,Weapon.go
@H_404_6@5个go文件
protobuf则不会,protobuf会全部生成到一个.pb.go文件中.这么比起来,FlatBuffers灵活度更高些.
@H_404_6@格式分析:
@H_404_6@"namespace MyGame;" :
会生成对应的MyGame目录
@H_404_6@ "mana:short = 150;" :
可以直接指定数据类型及默认值,且非常直观。
@H_404_6@" table Monster { pos:Vec3; ":
table可以直接嵌套struct
@H_404_6@ "friendly:bool = false (deprecated,priority: 1);" :
通过指定deprecated,可以删除掉此字段。
@H_404_6@attribute "priority" :
定义了priority关键字,用在friendly上,但从生成的Go文件来看,没看出有啥意义。
感觉可以忽略.
@H_404_6@"union Any { Monster,Weapon}" :
union相关的东西用在 "test:Any;" 上.
生成一个Any.go文件,里面的内容:
const ( AnyNONE = 0 AnyMonster = 1 AnyWeapon = 2 )可以看到相当于一个enum类型。
@H_404_6@"root_type Monster;root_type Weapon;"
root_type的作用:
在其table生成的go文件中,除Table中字段会生成相关函数外,
@H_404_6@会另外生成GetRootAsMonster()函数,便于调用
func GetRootAsMonster(buf []byte,offset flatbuffers.UOffsetT) *Monster {
如不用也可,没有太大影响。
@H_404_6@格式其它:
注释:
在FlatBuffers中用 " @H_404_6@///" 来表示。且此注释会带入到生成的源码文件中。
@H_404_6@效验:
1. 当使用了未定义的类型或定义时,会报错
2. 依顺序解析,如把最末的root_type Monster;提到table Monster前面,也会报错
@H_404_6@ required/optional :
struct的每个字段都为required
table的每个字段都默认都是optional,但可以指定为required
@H_404_6@ 指定Table字段函数生成顺序:
/// 加id指定生成顺序 table Monster { pos:Vec3 (id: 0); mana:short = 150 (id: 3); hp:short = 100 (id: 1); name:string (id: 2); //friendly:bool = false (deprecated,priority: 1); friendly:bool = false (deprecated,id: 4); //friendly:bool = false (priority: 1); inventory:[ubyte] (id: 6); color:Color = Blue (id: 5); test:Any (id: 8); }
依此为例,会按id指定顺序生成相关函数.
注意:
@H_404_6@如有加id,则table中所有字段都要加id才可通过
对于Any,可以看到id为8,而不是按顺序来的7.原来是它会生成:
func (rcv *Monster) TestType() byte {}
func (rcv *Monster) Test(obj *flatbuffers.Table) bool {}
即隐含一个Type的字段。所以要加1. 即@H_404_6@union型的,其id为{}内总个数加1.
@H_404_6@
@H_404_6@ 可以用include "include_test1.fbs"; 形式,将其它.fbs文件嵌套进来。
@H_404_6@使用方法:
@H_404_6@取值:
buf,err := IoUtil.ReadFile("monster.dat") offset := 0 monster := example.GetRootAsMonster(buf,offset) got := monster.Hp()直接得到即可。
@H_404_6@赋值:
可参考此代码:
builder := flatbuffers.NewBuilder(0)
str := builder.CreateString("MyMonster")
example.MonsterStart(builder)
example.MonsterAddPos(builder,example.CreateVec3(builder,1.0,2.0,3.0,4,5,6))
example.MonsterAddHp(builder,80)
example.MonsterAddName(builder,str)
example.MonsterAddInventory(builder,inv)
example.MonsterAddTestType(builder,1)
// example.MonsterAddTest(builder,mon2)
// example.MonsterAddTest4(builder,test4s)
_ = example.MonsterEnd(builder)
就到这了,速度啥的没做对比。 总的感觉是FlatBuffers定义起来简单,直观。
对Go支持很好,特别是分别生成一个个对应.go文件这点比较爽。其它待看。
MAIL: xcl_168@aliyun.com
BLOG:http://blog.csdn.net/xcl168

