Value and type (values and Types)
Lua is a dynamic type language, which means that variables have no type and only values have types. The language does not have a type definition, and all values carry their own type.
All values in Lua are class-one citizens, which means that all values can be stored in variables, passed as arguments to other functions, and returned as the result of the function.
It is important to note that this is also true for functions, which are not treated in Java. For example, to sort a list, a comparison function is required, and LUA can pass the comparison function directly, and Java needs to create a type for the comparison function and then pass an instance of that type.
To take a look at an example, arrange a list from large to small:
Lua
list = {12345}function comp(i, j) return i > jendtable.sort(list, comp)
Java
new ArrayList<Integer>(Arrays.asList(new12345new Comparator<Integer>(){ @Override publicintcompare(Integer o1, Integer o2) { return1 : -1; }};Collections.sort(list, comp);
LUA provides eight basic data types: Nil, Boolean, number, string, function, UserData, thread, table.
Nil: indicates null.
Boolean: Boolean type, only nil and false for false, and all others are true. Both 0 and 1 represent true.
Number: Numeric type, two internal representations, integer and float, default to 64-bit integers and double-precision floating-point types.
String: The value is immutable, and a new string object is created each time the modification occurs. Like Java's StringBuilder, LUA provides table.concat to stitch strings together.
Function: the type of functions. He is a class citizen.
UserData: Allows data in C to be saved in Lua. How does that work? Lua as an embedded language, its own API is very small, but it is easy to extend the function through C. For example, the socket function is provided for LUA so that it can be used as follows:
connection = socket.connect(host, port)connection.write(msg)
This connection is a connection object, which is a userdata created by CAPI and can be used in Lua.
Thread: A separate thread of execution used to implement the process. The thread of LUA differs from the thread of the operating system, and the instant operating system does not support Thread,lua to support the process on this operating system. (described later in the co-process)
Table: Tables, the only data structure of LUA. But it can be used to represent arrays, collections, linked lists, trees, graphs and other data structures.
Environment and Global Environment (Environmets and the Globals environment)
When referencing an undeclared variable var, the syntactic representation of _env.var. The value of _env is a table, which is called the environment. Each compiled chunk in Lua has an additional local variable, called _env. When accessing a non-local variable, it is looked up from _env, and when a non-local variable is defined, it is stored in _env.
There is a special environment in LUA called the Global Environment (_G), and the default value of _ENV is the global environment. So when you define a non-local variable, the default is the global variable.
If we define our own environment _env, then non-local variables will be stored in a custom environment, to take a look at an example (lua5.2 or later):
employee1 = {_G_G} -->保留全局环境的引用1 -->不会作为全局变量"xiaoming"3000_G employee2 = {_G_G2 "daming"20000_Gprint(employee1.id, employee1.name, employee1.salary)print(employee2.id, employee2.name, employee2.salary)
Fault handling (Error handing)
Lua is an embedded extension language, and all behavior starts with a C function call from the host program. When Lua compiles or runs an error, it gives control to the host program and the host program handles the error.
Lua can throw an error by using the error function. If Lua wants to catch errors, it needs to run the code in protected mode, that is, by Pcall or Xpcall to execute the method.
When using Xpcall, you need to provide an error handler that can be executed when the error occurs and the stack is not expanded. If the stack is not expanded, this means that you can get all the information for the calling context, such as a local variable in the current environment. However, it is not possible to use the information in the context directly in the error handling function, but with the debug library, consider an example:
function get1() Locali =1Get2 ()End function get2() Localj =2Get3 ()End function get3() LocalK =3 Error("Throw error")End function handler(msg) --print (Debug.traceback ())--the level at which the method is determined by the print stack backtracking informationName, value =Debug. getlocal (3,1)--Get the local variable K for the Get3 method Print(name, value) name, value =Debug. getlocal (4,1)--local variable J for getting the Get2 method Print(name, value) name, value =Debug. getlocal (5,1)--Get the local variable I of the Get1 method Print(name, value)return "Warp".. MsgEndXpcall(Get1, Handler)
Output:
k 3j 2i 1
MetaTable and meta-Methods (Metatables and Metamethods)
LUA provides a meta-table for each value, which is a table that defines the behavior of the original value under a particular operation. Behavior is provided by methods, which are called meta-methods. A meta-table can control many operations, such as addition, length, comparison, index, and so on.
Values for table and UserData types have separate meta-tables, and other types of values share a single meta table.
For example, our variables can be stored in three places, global domain, Session field, page field, and the lookup order is page,session,global. This can be done with a meta-table:
12}session_mt = {__index = global} -->定义元表session_mt和元方法__indexsetmetatable(session, session_mt) -->session中查找不到的key会去global中查找3}page_mt = {__index = session}setmetatable(page, page_mt)print(page.c, page.b, page.a)
Output:
3 2 1
Co-process (Coroutines)
The process in Lua is also called cooperative multi-threading, which does not preempt execution, and only the yield is called within the process to give up execution.
Each of the processes in Lua is a separate sequence of executions, and no memory is shared between the threads.
There are many features of the LUA process, such as the call resume after yield to continue execution, the execution proceeds from the last yield, and access to those local variables before yield.
Closures (Closure)
When function A calls function B, function B can manipulate local variables in function A, which is called closures. See an example:
function retfoo() local0 returnfunction () 1 return i endendfoo = retfoo()print(foo(), foo())
Output:
1 2
The purpose of closures is to preserve state and to have relationships between multiple invocations.
For statement
There are two forms of a for statement in Lua, numeric for and generic for.
- The syntax of numeric for IS as follows
forexpexpexpdoend
Block takes name as the loop variable, starting at the first exp, until the second exp, and the step is the third exp.
A numeric for like this:
fordoend
It is equivalent to the following code
Do LocalVAR, limit, step =Tonumber(E1),Tonumber(E2),Tonumber(E3)if not(Var andLimit andStep Then Error()Endvar = var-step while true Dovar = var + stepif(Step >=0 andvar > limit)or(Step <0 andvar < limit) Then Break End Localv = var blockEndEnd
- The syntax of generic for IS as follows
forindoendnamelist ::= Name {‘,’ Name}
A generic for like this:
forindoend
It is equivalent to the following code
do local f, s, var = explist whiletruedo local var_1, … , var_n = f(s, var) ifnilthenbreakend var = var_1 block endend
F, S, Var can be considered as iterative functions, iterative invariants, iterative variables.
So Lua iterators can be divided into two types, one stateful and one stateless.
Stateful iterators are implemented with closures, such as writing an iterator to traverse the table array.
function ipairs(table) -A stateful iteratori =0 return function() i = i +1 ifi > #Table Then return Nil End returnITableIEndEndTable= {"a","B","C","D","E"} forI, Vinch Ipairs(Table) Do Print(I, V)End
The disadvantage of stateful iterators is that each traversal requires an iterator to be created, and a stateless iterator is not required.
function ipairs0(table, i) -no State iteratori = i +1 Localv =TableIif notV Then return Nil End returnI, VEnd function ipairs(table) returnIpairs0,Table,0EndTable= {"a","B","C","D","E"} forI, Vinch Ipairs(Table) Do Print(I, V)End
In this example, Ipairs0, table, and I correspond to F, S, Var, respectively. In context, I is both an iterative variable and the current index of the table array.
Modules and packages (module and package)
From the user's point of view, a module is a library that can be loaded by require. Then we get a global variable that represents a table. This table is like a namespace whose content is everything that is exported in the module, such as functions and constants.
Loading a module
require “mod”mod.foo()
Write a module
Put the contents of the module to be exported in a table, with the module name as a global variable reference to the table, the module finally returns the table.
modulename = … -->模块名由require函数传入local moduletable = {} -->模块table,存放要导出的内容_G[modulename] = moduletable -->用模块名作为全局变量引用模块table-- 定义模块中要导出的函数和常量return moduletable -->相当于package.loaded[modulename] = moduletable
If a module is loaded, the Require function returns a module that has already been loaded. If the module requires a hot update, this can be done:
packagenilrequire “modulename”
There are, of course, more questions to consider in the actual code, such as Upvalue updates in closures.
Object oriented
For an object to have variables and methods, LUA can use table to represent objects.
18}function Girl.grow(self, v) end1)print(Girl.age)
Girl is an object, and age is a girl variable, and grow is the girl method. The first parameter of the Grow method is self, and in the example Girl.grow (Girl, 1) calls the Grow method, the Girl is passed in. This call has a different syntactic sugar:
Girl:grow(1)
The Grow method can be defined like this:
function Girl:grow(v) end
In object-oriented languages such as Java and C #, there is a distinction between classes and objects. A class is an abstraction of an object that is created through a class, such as Girl g = new Girl (). There is no concept of classes in Lua, and if you need to express classes, you can use the prototype language approach. Object A has a prototype B, and object A looks for a nonexistent operation on prototype B, and prototype B is also a normal object.
function Girl:new(o) or {} setmetatable(o, self) self.__index = self return oendfunction Girl:grow(v) self.age = self.age + vend18})g:grow(1)print(g.age)
Using a meta-table, LUA can also express the concept of inheritance, polymorphism. But I think Lua has a more flexible syntax, and there's no need to be as inflexible as object-oriented programming. For example, if you have GIRL1 and girl2 two objects, and their grow behavior is different, then you need to create GIRL1 and Girl2 two classes in object-oriented, whereas in Lua you simply modify Girl2 Grow method:
local oldGrow = g.growfunction g:grow(v) oldGrow(g, v) print("do other things...")endg:grow(1)print(g.age)
Resources
The second edition of LUA programming
Lua 5.3 Reference Manual
Lua 5.3 Cloud-inspired translation version
Lua summarizes a