Lua數(shù)據(jù)類型(源碼解析)

我們都知道Lua是一門(mén)動(dòng)態(tài)類型的腳本語(yǔ)言,也就是說(shuō)同一個(gè)變量可以在不同的時(shí)刻指向不同類型的數(shù)據(jù)挥等。例如

local a = nil
a = 1
a = "123"

而在Lua中有8中基礎(chǔ)的數(shù)據(jù)類型:nil(空)捕仔,boolean(布爾),number(數(shù)字)歧杏,string(字符串),table(表)迷守,function(函數(shù))犬绒,userdata(自定義類型),thread(協(xié)程)兑凿,那這幾種基礎(chǔ)類型在Lua中是怎么定義的凯力,而Lua又是怎么實(shí)現(xiàn)動(dòng)態(tài)類型的呢?

一礼华、C語(yǔ)言中實(shí)現(xiàn)通用數(shù)據(jù)結(jié)構(gòu)的設(shè)想

Lua是使用C語(yǔ)言實(shí)現(xiàn)的一種腳本語(yǔ)言咐鹤,那么我們?nèi)绻覀兿朐贑語(yǔ)言中實(shí)現(xiàn)一種新的通用的數(shù)據(jù)類型一般會(huì)怎么去做呢?
定義一個(gè)結(jié)構(gòu)體圣絮,這個(gè)結(jié)構(gòu)體中一定要有一個(gè)字段來(lái)存儲(chǔ)當(dāng)前結(jié)構(gòu)體所表示的數(shù)據(jù)類型祈惶,同時(shí)需要一些字段來(lái)存儲(chǔ)不同數(shù)據(jù)類型的具體數(shù)據(jù)

二、Lua中通用數(shù)據(jù)結(jié)構(gòu)的實(shí)現(xiàn)
2.1基本數(shù)據(jù)類型宏的定義

先看一下Lua中定義的幾種基本數(shù)據(jù)類型的宏:

//(lua.h)
/*
** basic types
*/
#define LUA_TNONE       (-1)
#define LUA_TNIL        0
#define LUA_TBOOLEAN        1
#define LUA_TLIGHTUSERDATA  2
#define LUA_TNUMBER     3
#define LUA_TSTRING     4
#define LUA_TTABLE      5
#define LUA_TFUNCTION       6
#define LUA_TUSERDATA       7
#define LUA_TTHREAD     8

這些宏對(duì)應(yīng)的數(shù)據(jù)類型如下表:


定義的宏對(duì)應(yīng)的數(shù)據(jù)類型.png

lua_Number對(duì)應(yīng)的C語(yǔ)言的基本數(shù)據(jù)類型double扮匠,所以Lua中的number類型表示的都是實(shí)數(shù)(雙精度浮點(diǎn)數(shù))捧请,Lua中沒(méi)有整數(shù)類型。

//(luaconf.h)
/*
** {==================================================================
@@ LUA_NUMBER is the type of numbers in Lua.
** CHANGE the following definitions only if you want to build Lua
** with a number type different from double. You may also need to
** change lua_number2int & lua_number2integer.
** ===================================================================
*/
#define LUA_NUMBER_DOUBLE
#define LUA_NUMBER  double
//(lua.h)
/* type of numbers in Lua */
typedef LUA_NUMBER lua_Number;

LUA_TLIGHTUSERDATA和LUA_TUSERDATA都是void *(指針類型)棒搜。根據(jù)名字我們知道他們對(duì)應(yīng)的是Lua的userdata基本數(shù)據(jù)類型疹蛉,但是兩者是有一些區(qū)別的。LUA_TLIGHTUSERDATA表示那些內(nèi)存分配與釋放都是由Lua外部的使用者要管理的對(duì)象力麸,而LUA_TUSERDATA表示的都是通過(guò)Lua來(lái)管理生命周期的對(duì)象可款,也就是LUA_TUSERDATA指向的對(duì)象是需要加入到Lua的GC(Garbage Collection 垃圾回收)中的育韩。

2.2需要GC的基本數(shù)據(jù)類型

我們知道Lua有自己的GC機(jī)制,那么哪些基礎(chǔ)數(shù)據(jù)類型需要加到GC中闺鲸,哪些又不需要筋讨,怎么區(qū)分呢?
在Lua中用一個(gè)宏來(lái)表示哪些數(shù)據(jù)類型需要進(jìn)行GC操作:

//(lobject.h)
#define ttype(o)    ((o)->tt)

#define iscollectable(o)    (ttype(o) >= LUA_TSTRING)

所以說(shuō)LUA_TSTRING之前的數(shù)據(jù)類型是都不需要GC摸恍,也就是string版仔,table,function误墓,userdata蛮粮,thread都需要GC的。
在Lua中需要進(jìn)行GC操作的數(shù)據(jù)類型都會(huì)有個(gè)CommonHeader宏定義的成員谜慌,并且這個(gè)成員在定義的最開(kāi)始部分然想。

/*
** Common Header for all collectable objects (in macro form, to be
** included in other objects)
*/
#define CommonHeader    GCObject *next; lu_byte tt; lu_byte marked
/*
** Common header in struct form
*/
typedef struct GCheader {
  CommonHeader;
} GCheader;

next : 指向下一個(gè)GC鏈表的成員
tt : 表示數(shù)據(jù)的類型,即前面的那些表示數(shù)據(jù)類型的宏
marked :GC時(shí)欣范,相關(guān)的標(biāo)記位变泄。
到了這里我們可以使用一個(gè)共同體(union),將所有需要進(jìn)行GC的數(shù)據(jù)類型囊括起來(lái):

//(lstate.h)
/*
** Union of all collectable objects
*/
union GCObject {
  GCheader gch;
  union TString ts;
  union Udata u;
  union Closure cl;
  struct Table h;
  struct Proto p;
  struct UpVal uv;
  struct lua_State th;  /* thread */
};

所以GCObject可以表示Lua中所有需要GC的數(shù)據(jù)類型。

2.3Lua中所有數(shù)據(jù)類型表示

既然所有需要GC的數(shù)據(jù)類型使用GCObject表示恼琼,那么同理所有的數(shù)據(jù)類型也可以用一個(gè)共同體表示:

//(lobject.h)
/*
** Union of all Lua values
*/
typedef union {
  GCObject *gc;
  void *p;
  lua_Number n;
  int b;
} Value;

結(jié)合我們(一)中所說(shuō)的妨蛹,我們現(xiàn)在有了可以表示所有類型數(shù)據(jù)的Value了,那么就還需要一個(gè)表示數(shù)據(jù)類型的字段晴竞,所以Lua中給我們定義了一個(gè)TValue的結(jié)構(gòu)體:

//(lobject.h)
/*
** Tagged Values
*/

#define TValuefields    Value value; int tt

typedef struct lua_TValue {
  TValuefields;
} TValue;

從這個(gè)結(jié)構(gòu)體我們可以看到使用int類型的tt字段表示當(dāng)前的數(shù)據(jù)類型蛙卤,使用Value來(lái)表示任意類型的值。這樣TValue就可以表示Lua中任意的數(shù)據(jù)類型了噩死。
我們用一個(gè)圖來(lái)表示一下Lua通用的數(shù)據(jù)結(jié)構(gòu)的組織:


Lua通用數(shù)據(jù)類型組織結(jié)構(gòu).png
三颤难、通用類型與具體類型轉(zhuǎn)換
3.1判斷是否是具體的數(shù)據(jù)類型
//(lobject.h)
/* Macros to test type */
#define ttype(o)    ((o)->tt)
#define ttisnil(o)  (ttype(o) == LUA_TNIL)
#define ttisnumber(o)   (ttype(o) == LUA_TNUMBER)
#define ttisstring(o)   (ttype(o) == LUA_TSTRING)
#define ttistable(o)    (ttype(o) == LUA_TTABLE)
#define ttisfunction(o) (ttype(o) == LUA_TFUNCTION)
#define ttisboolean(o)  (ttype(o) == LUA_TBOOLEAN)
#define ttisuserdata(o) (ttype(o) == LUA_TUSERDATA)
#define ttisthread(o)   (ttype(o) == LUA_TTHREAD)
#define ttislightuserdata(o)    (ttype(o) == LUA_TLIGHTUSERDATA)

o為通用數(shù)據(jù)類型TValue,tt則為T(mén)Value結(jié)構(gòu)體中表示具體數(shù)據(jù)類型的字段。

3.2獲得具體數(shù)據(jù)類型的值
//(lobject.h)
#define gcvalue(o)  check_exp(iscollectable(o), (o)->value.gc)
#define pvalue(o)   check_exp(ttislightuserdata(o), (o)->value.p)
#define nvalue(o)   check_exp(ttisnumber(o), (o)->value.n)
#define rawtsvalue(o)   check_exp(ttisstring(o), &(o)->value.gc->ts)
#define tsvalue(o)  (&rawtsvalue(o)->tsv)
#define rawuvalue(o)    check_exp(ttisuserdata(o), &(o)->value.gc->u)
#define uvalue(o)   (&rawuvalue(o)->uv)
#define clvalue(o)  check_exp(ttisfunction(o), &(o)->value.gc->cl)
#define hvalue(o)   check_exp(ttistable(o), &(o)->value.gc->h)
#define bvalue(o)   check_exp(ttisboolean(o), (o)->value.b)
#define thvalue(o)  check_exp(ttisthread(o), &(o)->value.gc->th)
#define l_isfalse(o)    (ttisnil(o) || (ttisboolean(o) && bvalue(o) == 0))
3.3設(shè)置具體數(shù)據(jù)類型的值
//(lobject.h)
/* Macros to set values */
#define setnilvalue(obj) ((obj)->tt=LUA_TNIL)

#define setnvalue(obj,x) \
  { TValue *i_o=(obj); i_o->value.n=(x); i_o->tt=LUA_TNUMBER; }

#define setpvalue(obj,x) \
  { TValue *i_o=(obj); i_o->value.p=(x); i_o->tt=LUA_TLIGHTUSERDATA; }

#define setbvalue(obj,x) \
  { TValue *i_o=(obj); i_o->value.b=(x); i_o->tt=LUA_TBOOLEAN; }

#define setsvalue(L,obj,x) \
  { TValue *i_o=(obj); \
    i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TSTRING; \
    checkliveness(G(L),i_o); }

#define setuvalue(L,obj,x) \
  { TValue *i_o=(obj); \
    i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TUSERDATA; \
    checkliveness(G(L),i_o); }

#define setthvalue(L,obj,x) \
  { TValue *i_o=(obj); \
    i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TTHREAD; \
    checkliveness(G(L),i_o); }

#define setclvalue(L,obj,x) \
  { TValue *i_o=(obj); \
    i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TFUNCTION; \
    checkliveness(G(L),i_o); }

#define sethvalue(L,obj,x) \
  { TValue *i_o=(obj); \
    i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TTABLE; \
    checkliveness(G(L),i_o); }

#define setptvalue(L,obj,x) \
  { TValue *i_o=(obj); \
    i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TPROTO; \
    checkliveness(G(L),i_o); }

#define setobj(L,obj1,obj2) \
  { const TValue *o2=(obj2); TValue *o1=(obj1); \
    o1->value = o2->value; o1->tt=o2->tt; \
    checkliveness(G(L),o1); }
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末已维,一起剝皮案震驚了整個(gè)濱河市行嗤,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌垛耳,老刑警劉巖栅屏,帶你破解...
    沈念sama閱讀 218,386評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異堂鲜,居然都是意外死亡栈雳,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,142評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門(mén)泡嘴,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)甫恩,“玉大人,你說(shuō)我怎么就攤上這事酌予』腔” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,704評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵抛虫,是天一觀的道長(zhǎng)松靡。 經(jīng)常有香客問(wèn)我,道長(zhǎng)建椰,這世上最難降的妖魔是什么雕欺? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,702評(píng)論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮棉姐,結(jié)果婚禮上屠列,老公的妹妹穿的比我還像新娘。我一直安慰自己伞矩,他們只是感情好笛洛,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,716評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著乃坤,像睡著了一般苛让。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上湿诊,一...
    開(kāi)封第一講書(shū)人閱讀 51,573評(píng)論 1 305
  • 那天狱杰,我揣著相機(jī)與錄音,去河邊找鬼厅须。 笑死仿畸,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的朗和。 我是一名探鬼主播颁湖,決...
    沈念sama閱讀 40,314評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼例隆!你這毒婦竟也來(lái)了甥捺?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,230評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤镀层,失蹤者是張志新(化名)和其女友劉穎镰禾,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體唱逢,經(jīng)...
    沈念sama閱讀 45,680評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡吴侦,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,873評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了坞古。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片备韧。...
    茶點(diǎn)故事閱讀 39,991評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖痪枫,靈堂內(nèi)的尸體忽然破棺而出织堂,到底是詐尸還是另有隱情叠艳,我是刑警寧澤,帶...
    沈念sama閱讀 35,706評(píng)論 5 346
  • 正文 年R本政府宣布易阳,位于F島的核電站附较,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏潦俺。R本人自食惡果不足惜拒课,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,329評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望事示。 院中可真熱鬧早像,春花似錦、人聲如沸肖爵。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,910評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)遏匆。三九已至法挨,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間幅聘,已是汗流浹背凡纳。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,038評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留帝蒿,地道東北人荐糜。 一個(gè)月前我還...
    沈念sama閱讀 48,158評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像葛超,于是被迫代替她去往敵國(guó)和親暴氏。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,941評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • Lua內(nèi)部采用一種通用的基礎(chǔ)數(shù)據(jù)結(jié)構(gòu)來(lái)表示所有數(shù)據(jù)類型绣张,Lua語(yǔ)言及其精簡(jiǎn)答渔,只有字符串和表兩種最基本的數(shù)據(jù)結(jié)構(gòu)。然...
    JunChow520閱讀 2,311評(píng)論 0 1
  • 1. 寫(xiě)在前面 很多時(shí)候我們都需要借助一些腳本語(yǔ)言來(lái)為我們實(shí)現(xiàn)一些動(dòng)態(tài)的配置侥涵,那么就會(huì)涉及到如何讓腳本語(yǔ)言跟原生語(yǔ)...
    杰嗒嗒的阿杰閱讀 3,432評(píng)論 9 31
  • lua 的值類型 lua 是動(dòng)態(tài)類型的語(yǔ)言沼撕,即是說(shuō)類型附著于值而不是變量。在 lua 腳本里芜飘,變量是沒(méi)有類型的务豺,只...
    董噠噠閱讀 2,594評(píng)論 1 1
  • 開(kāi)篇 上一節(jié)分析了 lua_arith 的大部分代碼,由于篇幅原因嗦明,留到本節(jié)將繼續(xù)講解剩余的部分: 解析 現(xiàn)在我們...
    碼上說(shuō)閱讀 814評(píng)論 0 1
  • 第一篇 語(yǔ)言 第0章 序言 Lua僅讓你用少量的代碼解決關(guān)鍵問(wèn)題笼沥。 Lua所提供的機(jī)制是C不擅長(zhǎng)的:高級(jí)語(yǔ)言,動(dòng)態(tài)...
    testfor閱讀 2,672評(píng)論 1 7