Lua - 基础类型定义

Posted Lua探索之旅

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Lua - 基础类型定义相关的知识,希望对你有一定的参考价值。

静态or动态

静态类型语言(c/c++、java、c#、golang)里,每个变量必须显式的指定其类型,如下所示:

int a = 1;
string s = "good";


而在动态类型语言(python、lua、php、js)里,不需要为变量指定其类型,如下所示:

a = 1
s = "good"


看上去动态类型更符合用户习惯,用户只需知道value的格式,而不用关心系统内部用什么类型表示。相信每个学过c语言的人,都被指针这个概念迷惑了很久,假如大家一开始学习的是python,我相信会好很多。


静态和动态类型的区别在于类型检查的时机,静态类型一般在编译期执行类型检查,而动态类型在运行时检查类型,这两种方式各有优缺点,这里只说缺点:

  • 静态类型:不够灵活,比如C++严重依赖模板泛型编程,最新的c++11以及后续版本几乎全是泛型编程,传统C++程序员几乎要从精通到重新入门。

  • 动态类型:过于灵活,一段错误代码如果没被执行到,可能运行几个月都没被人发现,调试不便,需要通读代码才能理解程序。


Lua语言是一门典型的动态类型语言,比如定义函数时不需要写参数类型:

function max(a, b)
 if a>b then return a end
 return b
end

可以看到,动态语言天生具备泛型能力,那么在Lua里如何表示一个变量呢?



Object通用类型

如果能用一种通用类型(比如Object)表达所有类型,那么就相当于为每个变量添加了类型,上面的代码可改写为:

Object a = 1
Object s = "good"

function max(Object a, Object b)
 if a>b then return a end
 return b
end

假定Object类型是编译器自动添加的,那么就和静态类型一致了。现在的问题是如何用Object表示所有类型?


一个被很多人遗忘的C语言关键字union闪亮登场,union用来表示联合体,多个成员共享一份存储空间,以占用空间最大的成员为实际占用空间。


数值、字符串、table这3种类型为例,代码如下:

struct Object {
 union {
   double num;
   char* str;
   table* tb;
 } value;

 int type;
};
  • type存储实际类型

  • 数值用num成员

  • 字符串用str成员

  • table用tb成员

  • 以最大成员double为准,一个union占用8个字节


这里引出一个新的概念:值类型和引用类型。在C#和java里有这两种概念,值类型一般为基本的int、double、bool等简单类型,引用类型为类、数组、字符串等。


在Lua内部实现里(用户不需要知道这些类型的存在):

  • 值类型包括number、bool、light userdata

  • 引用类型包括string、userdata、closure、table、proto、upvalue、thread


union结构表示时,值类型使用原始类型,引用类型使用指针,如下所示:

struct Object {
 union {
   /*值类型*/
   double num;
   bool b;
   void* light_userdata;

   /*引用类型*/
   string* str;
   userdata* udata;
   closure* cl;
   table* tb;
   proto* p;
   upvalue* upval;
   thread* td;
 };

 int type;
};

这样就能用一种通用类型Object表达所有类型,且区分值类型和引用类型。


实例分析:

a = 1
s = "good"


对应的内部逻辑为:

Object a, s;

Object obj1;
obj1.type = INT;
obj1.num = 1;
a = obj1;

Object objstr;
objstr.type = STRNG;
objstr.str = new string("good")
s = objstr;


假如要对类型进行扩展,比如支持int64,考虑到int64是值类型,扩展后的Object如下所示:

struct Object {
 union {
   /*值类型*/
   double num;
   bool b;
   void* light_userdata;
   int64_t i64;  /* 新增类型 */

   /*引用类型*/
   string* str;
   userdata* udata;
   closure* cl;
   table* tb;
   proto* p;
   upvalue* upval;
   thread* td;
 };

 int type;
};

由于int64和double都是8个字节,Object的大小没有增加。


除了union联合体之外,还可以用类继承方式实现通用类型,比如Python就是通过PyObject*表示所有类型,代码如下:

typedef struct _object {
 PyObject_HEAD
} PyObject;

typedef struct {
 PyObject_HEAD
 long ob_ival;
} PyIntObject;

typedef struct {
 PyObject_VAR_HEAD
 PyObject **ob_item;
 Py_ssize_t allocated;
} PyListObject;


可以看到,PyIntObject和PyListObject的第一个字段是PyObject,这样变相实现了C++的继承语法,任何需要类型的地方的都可以用PyObject*代替。


关于动态语言的通用类型介绍到这里,各位有什么想法或建议可以留言哦~~


以上是关于Lua - 基础类型定义的主要内容,如果未能解决你的问题,请参考以下文章

lua基础知识(基于RUNOOB总结)

lua基础知识(基于RUNOOB总结)

Lua中的类型与值

Lua基础(转)

lua的基本语法

Lua5.4源码阅读—数据类型