這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
試用了下FlatBuffers,把一些東東記錄一下。
FlatBuffers 官網: http://google.github.io/flatbuffers/md__go_usage.html
它支援產生Go語言相關的東西,總的使用步驟如下:
1. 定義IDL 介面定義檔案,通常命名為.fbs
參考: Writing a schema
http://google.github.io/flatbuffers/md__schemas.html
2. 利用flatc 解析產生語言的檔案
flatc
參考: Using the schema compiler
http://google.github.io/flatbuffers/md__compiler.html
產生Go的參數:
-g : Generate Go classes. Skipped for data.
3. 在Go工程中安裝FlatBuffers的Go支援包,就可以在代碼直接使用了.
再詳細說說FlatBuffers的一些特性。先上一份.fbs的例子:
// example IDL filenamespace 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作例子來說明一下.
IDL產生結果:
會在MyGame下,產生Any.go,Color.go,Monster.go,Vec3.go,Weapon.go
5個go檔案
protobuf則不會,protobuf會全部產生到一個.pb.go檔案中.這麼比起來,FlatBuffers靈活度更高些.
格式分析:
"namespace MyGame;" :
會產生對應的MyGame目錄
"mana:short = 150;" :
可以直接指定資料類型及預設值,且非常直觀。
" table Monster { pos:Vec3; ":
table可以直接嵌套struct
"friendly:bool = false (deprecated, priority: 1);" :
通過指定deprecated,可以刪除掉此欄位。
attribute "priority" :
定義了priority關鍵字,用在friendly上,但從產生的Go檔案來看,沒看出有啥意義。
感覺可以忽略.
"union Any { Monster, Weapon}" :
union相關的東西用在 "test:Any;" 上.
產生一個Any.go檔案,裡面的內容:
const (AnyNONE = 0AnyMonster = 1AnyWeapon = 2)
可以看到相當於一個enum類型。
"root_type Monster;root_type Weapon;"
root_type的作用:
在其table產生的go檔案中,除Table中欄位會產生相關函數外,
會另外產生GetRootAsMonster()函數,便於調用
func GetRootAsMonster(buf []byte, offset flatbuffers.UOffsetT) *Monster {
如不用也可,沒有太大影響。
格式其它:
注釋:
在FlatBuffers中用 "
///" 來表示。且此注釋會帶入到產生的源碼檔案中。
效驗:
1. 當使用了未定義的類型或定義時,會報錯
2. 依順序解析,如把最末的root_type Monster;提到table Monster前面,也會報錯
required/optional :
struct的每個欄位都為required
table的每個欄位都預設都是optional,但可以指定為required
指定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指定順序產生相關函數.
注意:
如有加id,則table中所有欄位都要加id才可通過
對於Any,可以看到id為8,而不是按順序來的7.原來是它會產生:
func (rcv *Monster) TestType() byte {}
func (rcv *Monster) Test(obj *flatbuffers.Table) bool {}
即隱含一個Type的欄位。所以要加1. 即union型的,其id為{}內總個數加1.
支援.fbs檔案的嵌套:
可以用 include "include_test1.fbs"; 形式,將其它.fbs檔案嵌套進來。
使用方法:
取值:
buf, err := ioutil.ReadFile("monster.dat") offset := 0 monster := example.GetRootAsMonster(buf, offset) got := monster.Hp()直接得到即可。
賦值:
可參考此代碼:
builder := flatbuffers.NewBuilder(0)str := builder.CreateString("MyMonster")example.MonsterStart(builder)example.MonsterAddPos(builder, example.CreateVec3(builder, 1.0, 2.0, 3.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