1 简介

这一节我们先系统了解一下Lua语言的基础语法。Lua语言的核心由纯C语言实现,因此它体积小、运行轻量,同时非常依赖宿主程序进行调用和集成。当然,Lua也支持将C函数直接注册到运行环境中使用,所以在嵌入式开发、脚本扩展和游戏开发场景里都具备很强的灵活性。
2 语法约定
Lua语法规则建立在BNF(巴科斯-诺尔范式)的基础之上。此外,Lua对大小写非常敏感,这一点和许多常见动态编程语言类似,编写代码时需要特别注意。
2.1 保留关键字
熟悉C语言的读者可能会注意到,Lua中包含一些C语言没有的保留关键字,主要如下:
and elseif function
in nil local not or
repeat then until
在实际开发中,一个常见且实用的命名规范是:全局变量通常以下划线开头,这样更方便快速识别变量的作用域和用途。
2.2 操作符
Lua中有几个C语言没有的常用操作符:
^ —— 用于幂运算
~= —— 不等于
// —— 向下取整除法
相反,C语言中存在、但Lua里没有的操作符包括:
+=
-=
因此,在编写Lua表达式时需要稍微适应一下,尤其不能直接使用这类复合赋值运算符。
2.3 字符串定义
Lua字符串的定义方式主要有两种。第一种是使用转义字符,适合处理可能产生歧义的内容。比如说:
a 直接代表字符 a
97 也代表字符 a
\049 代表数字字符 '1'
这里需要注意,数字字符必须写成三位数,而其他字符的长度不能超过三位。除此之外,还有一些常见转义符:
\n 表示换行符(也就是字符串中直接写 \n)
如果直接写 n,那么它仅仅表示普通字母 n,并不具备换行含义。
第二种写法是使用长括号。长括号中的所有内容都会按普通字符处理,因此在处理多行文本或避免复杂转义时会更加方便。例如:
[[]] 是0级长括号
[==[]==] 是2级长括号
长括号等级越高,字符串嵌套和特殊内容处理就越灵活。
3 值与类型
Lua是一门典型的动态类型语言,这意味着变量本身并不固定属于某一种类型,真正带有类型信息的是“值”本身。一个值在创建时,就已经确定了自己的数据类型。
Lua总共定义了八种基本数据类型:nil、boolean、number、string、function、userdata、thread、table。一个非常重要的Lua语法细节是:只有nil和false会被判断为假,除此之外的所有值都会被视为真。
userdata类型通常用于保存C语言中的原始数据。Lua可以操作这种数据,但不能直接创建或修改它,因此宿主程序能够更好地控制底层数据。thread类型主要用于实现协程(coroutine),而table则通常用于实现关联数组、映射结构以及更复杂的数据组织方式。
table可以说是Lua中最核心、也最灵活的部分。它允许使用任意类型的值作为索引,也允许在表的字段中保存任意类型的数据(但不能是nil)。从某种意义上说,table是Lua唯一的通用数据结构;又因为函数本身也是值,所以你完全可以把函数存入table中,这使Lua的数据组织和程序设计方式都非常自由。
function、userdata、thread、table这几种类型的值都属于对象。也就是说,这类变量保存的是引用而不是实体本身,因此在赋值、传参和返回时都不会产生实际拷贝。如果想查看某个变量的类型,可以直接使用Lua标准库函数 type()。
3.1 强制转换
Lua比较智能的一点在于,它支持数字和字符串之间的自动转换。如果你希望更精确地控制数字转字符串的过程,可以使用 format 函数进行格式化输出,这在字符串处理和结果展示中非常常见。
4 变量
在Lua中,变量主要分为三类:全局变量、局部变量,以及表中的域。
函数外定义的变量默认都是全局变量,除非你使用 local 进行显式声明。函数内部的变量和函数参数默认则是局部变量。局部变量的作用域从声明位置开始,一直持续到当前语句块结束,或者持续到下一个同名局部变量出现为止。无论是哪种变量,在没有被赋值之前,它们的默认值都是nil。
a = 5 -- 全局变量
local b = 5 -- 局部变量
function joke()
c = 5 -- 全局变量(因为在函数内,但没加local)
local d = 6 -- 局部变量
end
print(c,d) --> nil nil
do
local a = 6 -- 局部变量(块内)
b = 6 -- 全局变量(注意没加local)
print(a,b) --> 6 6
end
print(a,b) --> 5 6
在上面这段Lua示例代码中,--> 用来表示前面表达式对应的输出结果,这是一种便于阅读和讲解的注释写法。
4.1 索引
对table进行索引时,最基础的方式是使用方括号 [],例如 t[i]。不过,Lua还提供了非常实用的语法糖:如果索引键是字符串类型,就可以直接使用点操作符写成 t.i,这样代码会更简洁。实际上,每一次索引访问的底层行为,本质上都类似于调用 gettable_event(t,i) 这样的函数过程。
4.2 环境表
所有全局变量都会被放在一个称为环境表的容器中,这个表的变量名是 _env。比如访问全局变量 a,本质上就等同于访问 _env.a。每个函数都会持有一个环境表的引用,这个环境表中保存了该函数能够访问到的所有变量。子函数通常会继承父函数的环境表。你还可以通过 getfenv / setfenv 这两个函数来读取或修改环境表,因此在变量控制和运行环境管理方面具有很高的灵活性。
以上就是Lua基本语法中比较核心的几个知识点。掌握这些Lua入门基础之后,后续再继续学习Lua高级特性、协程机制、表操作和函数式编程方式时,整体理解会更加顺畅。
