Lua语言中的标识符(或名称)是有任意字母、数字和下划线组成的字符串(注意,不能以数字开头)
Lua语言中有8种基本类型:nil(空)、boolean(布尔)、number(数值)、string(字符串)、userdata(用户数据)、function(函数)、thread(线程)和table(表)。使用函数type可获取一个值对应的类型名称
在条件测试中。将除了Boolean值false和nil外的所有其他值视为真。特别是。在条件检测中Lua语言把零和空字符也都视为真
and和or都遵循短路求值原则
当整型操作时出现比mininteger更小或者比maxinteger更大数值时,结果就会回环
整型的范围是10^19。浮点数型能够表示的整数范围被精确地限制在[-2^53,2^53]之间
Lua语言中的字符串是不可变值
使用双引号和单引号字符串是等价的
【表】
Lua语言中的表本质上是一种辅助数组,这种数组不仅可以使用数值作为索引,也可以使用字符串或其他任意类型的值作为索引(nil除外)
表是一个动态分配的对象,程序只能操作指向表的引用(或指针)
使用构造表达式创建表,其最简单的形式是{}
表永远是匿名的,表本身和保存表的变量之间没有固定的关系
同一个表中储存的值可以具有不同的类型引用
未经初始化的表元素为nil,将nil赋值给表元素可以将其删除。
当被用做表索引时,任何能够被转换为整型的浮点数都会被转换成整型数
把所有元素都不为nil的数组称为序列。
Lua语言提供了获取所有长度的操作符#。正如我们之前所看到,对于字符串而言,该操作符返回字符串的字节数;对于表而言,该操作符返回表对应序列的长度。
Lua语言中一种与众不同但又非常有用的特性是允许一个函数返回多个结果的,只需在return关键字后列出所有要返回的值即可。
当函数被作为一个单独语句调用的时,其返回值都会被丢弃;当函数被作为表达式调用时,将只保留第一个返回值。只有当函数调用是一系列表达式中的最后一个表达式是,其所有返回值才能被获取到。这里所谓的“一系列表达式”在Lua中表现为4种情况:多重赋值、函数调用时传入的实参列表、表构造器和return语句。
多重赋值中,如果一个函数没有返回值或者返回值个数不够多,那么Lua语言会用nil来补缺失的值。
可变长参数函数(variadic),参数列表中的三个点(…)表示该函数的参数是可变长的。
【编译、执行和错误】
函数loadfile也是从文件中加载Lua代码段,但它不会运行代码,而是只是编译代码,然后将编译后的代码段作为一个函数返回。与函数dofile不同,函数loadfile只返回错误码而不是抛出异常。
如果需要多次运行同一个文件,那么只需调用一次loadfile函数后再次多次调用它的返回结果即可。
要在Lua代码中处理错误,就应该使用函数pcall来封装代码
函数pcall会以一种保护模式来调用它的第一个参数,以便捕获该函数执行中的错误,无论是否有错误发生,函数pcall都不会引发错误。如果没有错误发生,那么pcall返回true及被调用函数的所有返回值;否则,则返回false以及错误信息。
通过error来抛出异常(throw an exception),然后用函数pcall来捕获(catch)异常,而错误信息则用来标识错误的类型。
Lua语言提供了函数xpcall。该函数与pcall函数类似,但它的第二个参数是一个信息处理函数。当发生错误时,lua会调用栈展开前调用这个信息处理函数,以便消息处理函数能够使用调用库来获取有关错误的更多信息。两个常用的信息处理函数是debug.debug和debug.traceback,前者为用户提供了一个lua提示符来让用户检查错误的发生的原因;后者则使用调用栈来构造详细的错误信息。
【模块和包】
函数requier在表中package.loaded中检查模块是否已被加载。
模块在任何情况下只能加载一次;至于如何处理冲突的加载,取决于模块自己。
Lua支持具有层次结构的模块名,通过点来分隔名称中的层次。
【迭代器和泛型for】
一个闭包就一个可以访问其自身的环境中一个或多个局部变量的函数。
一个闭包结构通常涉及两个函数:闭包本身和一个用于创建该闭包及其封装变量的工厂。
泛型for为一次迭代循环做了所有的记录工作:它在内部保存了迭代函数,因此不需要变量iter;它在每次做新的迭代时都会再次调用迭代器,并在迭代器返回nil时结束循环。
泛型for保存了三个值:一个迭代函数、一个不可变状态和一个控制变量。
【垃圾收集】
Lua语言通过垃圾收集自动地删除成为垃圾的对象
弱引用表(weak table)、析构器(finalizer)和函数collectgarbage是在Lua语言中用来辅助垃圾收集器的主要机制。
所谓弱引用是一种不再垃圾收集器考虑范围内的对象引用。如果对一个对象的所有引用都是弱引用,那么垃圾收集器将会回收这个对象并删除这些弱引用。
不论哪种类型的弱引用表,只要有一个键或值被回收了,那么对应的整个键值对都会被从表中删除。
请注意,只有对象可以从弱引用表中被移除,而像数字和布尔这样的“值”是不可回收的
所以,字符串就像数值和布尔值一样,对于一个字符串类型的键来说,除非它对应的值被回收,否则是不会从弱引用表中移除的。
空间换时间是一种常见的编程技巧。我们可以通过记忆函数的执行结果,在后续使用相同参数再次调用该函数时直接返回之前记忆的结果,来加快函数的运行速度。
记忆技术还可以用来确保某类对象的唯一性。
弱引用表的另外一种重要的应用是将属性与对象关联起来。创建唯一键的一种简答和防止出错的方法是创建一个新表并把它当作键来使用。
在Lua语言中,一个具有弱引用键和强引用值的表是一个瞬表。在一个瞬表中,一个键的可访问性控制着对应值的可访问性。更确切地说,考虑瞬表中的一个元素(k,v),指向的v的引用只有当存在某些指向k的其他外部引用存在时才是强引用,否则即使v(直接或者间接地)引用了k,垃圾收集器最终会收集k并把元素从表中移除。
析构器是一个与对象关联的函数,当该对象即将被回收该函数会被调用。
Lua语言中,析构器的一个微妙之处在于“将一个对象标记为需要析构”的概念。
如果真的需要在后续设置元方法,那么可以给字段__gc先赋一个任意值作为占位符。
当垃圾收集器在同一个周期中析构多个对象时,它会按照对象被标记为需要析构处理的顺序逆序调用这些对象的析构器。
有关析构器的另一个微妙之处是复苏。由于复苏的存在,Lua语言会在两个阶段中回收具有析构器的对象。
在每个垃圾收集周期内,垃圾收集器会在调用析构器之前清理弱引用表中的值,在调用析构器之后再清理键。
每一个垃圾收集周期由四个阶段组成:标记、清理、清除、析构。
通过函数collectgarbage可以对垃圾收集器进行一些额外的控制,该函数实际上是几个函数的集合体:第一个参数是可选的字符串,用来说明进行何种操作;有些选项使用一个整型作为第二个参数,称为data.
参数pause用于控制垃圾收集器在一次收集完成后等待多久再开始新的一次收集。通常,我们应该把这个值设在0到200%之间。
参数stepmul控制对于每分配1KB内存,垃圾收集器应该进行多少工作,这个值越高,垃圾收集器使用的增量越小。默认值是200%。
【协程Coroutine】
协程却需要彼此协作地运行,即在任意指定的时刻只能有一个协程运行,且只有正当运行的协程显式地要求被挂起时其执行才会暂停。
一个协程有以下四种状态,即挂起、运行、正常和死亡。我们可以通过函数coroutine.status来检查协程的状态
Lua语言中一个非常有用的机制是通过一对resume-yield来交换数据。第一个resume函数(没有对应等待它的yield)会把所有其他的额外参数传递给协程的主函数。