Lua provides advanced require functions to load the Runtime Library. Roughly speaking, require and dofile perform the same function, but there are two differences:
1.Require searches for directories to load files.
2.Require checks whether the file has been loaded to avoid repeated loading of the same file..
Because of the above features, require is a better function for loading databases in Lua.
The path used by require is different from the path we see in general. The path we usually see is a directory list. The require path is a list of modes. Each mode indicates a method to convert a Virtual File Name (the require parameter) to a real file name. More specifically, each pattern is a file name containing an optional question mark. When matching, Lua will first Replace the question mark with a virtual file name, and then check whether such a file exists. If there is no match, use the same method to use the second pattern. For example, the path is as follows:
?;?.lua;c:\windows\?;/usr/local/lua/?/?.lua
When you call require "Lili", you will try to open these files:
lililili.luac:\windows\lili/usr/local/lua/lili/lili.lua
Require focuses only on semicolons (separators between modes) and question marks. Other information (directory separator, file extension) is defined in the path.
To determine the path, Lua first checks whether the global variable lua_path is a string. If so, the string is regarded as the path; otherwise, require checks the value of the environment variable lua_path, if both fail; require uses a fixed path (typical "?;?. Lua ")
Another feature of require is to avoid repeated loading of the same file twice. Lua retains a list Of all loaded files (saved using table ). If a file to be loaded has a simple require return in the table, the virtual name of the file to be loaded is retained in the table, instead of the actual file name. Therefore, if you use different Virtual File Names (require) for the same file twice, the file will be loaded twice. For example, for require "foo" and require "foo. Lua", the path is "?;?. Lua "loads Foo. Lua twice. We can also use the global variable _ loaded to access the file name list, so that we can determine whether the file has been loaded. We can also use a small trick to let require load a file twice. For example, after require "foo", _ loaded ["foo"] will not be nil. We can assign it to nil, and require "foo. Lua" will load the file again.
The pattern in a path can also contain no question mark but a fixed path, for example:
?;?.lua;/usr/local/default.lua
In this case, this fixed file will be used when require does not match (of course, this fixed path must be placed at the end of the mode list to make sense ). Before require runs a chunk, it defines a global variable _ requiredname to save the file name of the virtual file to be required. We can use this technique to extend the require function. For an extreme example, we can set the path to "/usr/local/Lua/newrequire. lua ", so that newrequire will be run every time you call require. lua. In this case, you can use the value of _ requiredname to actually load the required file.
Dofile:
We know that a Lua file exists as a code block (chunk) and its essence is a function. The simplest thing is, I write a piece of code in an external Lua file, then, use dofile in the main Lua file, and the code block of the external file will be executed.
The external Lua file does not involve the lexical domain during compilation:
-- Outer. Lua: function sayhello () print (name .. ", hello! ") End -- mian. Lua: require (" outer ") name =" Lei Shu "local name =" niu Shu "sayhello ()
The running result is "Hello, Uncle Lei !"
Similar to # include <...> in C language, functions defined elsewhere can be called after file introduction. However, Lua is not a language for separation of definition and implementation, so it loads the entire definition. Generally, Lua loads the external file first and then runs it. In fact, this external code can return values, and its return value is the return value of require. Here we do not return any values. The result of executing this external code is to define such a global function. Note that it is a global function. Although the functions we define directly are global functions, we have not paid much attention to it. If we need to define a local function, it will not be seen in the main program block. In addition, as in the previous situation, the external code block only knows "Lei Shu", and "niu Shu" does not know who it is.
You can define a bunch of functions in an external file and add them all to the global environment. But be careful when using global things. One principle is that the smaller the global pollution, the better. Naturally, the concept of "module" is introduced. In Lua, the module acts as a universal table. The most natural idea is to define a table, put the function to be defined in this table, and finally return this table.
The require mechanism in Lua:
To facilitate code management, Lua code is usually divided into different modules and loaded in through the require function.
Now let's take a look at the Lua require processing process.
1. Data and functions related to the require Mechanism
Package. path: stores the search path of the loaded external module (the concept of "module" and "file" in Lua is vague, because the value plays a different role at different times, this path is "template-based path", which contains replaceable symbols "? ", This symbol will be replaced, and Lua will check whether the file exists. If yes, it will call a specific interface. Typical values:
"./?. Lua ;./?. LC;/usr/local /? /Init. Lua"
If you call require ("Hello. World") in Lua code ")
Then Lua will search for the following in sequence:
./Hello/World. Lua => here, "Hello. World" is changed to "Hello/World" and the model is replaced "./?. Lua"
./Hello/World. LC
.....
(This processing method is similar to Python, except that _ init _ is not required __. PY, you can also call _ init _ in Python __. PY) package. PATH is set when the VM is started. If the environment variable lua_path exists, use this environment variable as its value and replace ";" with luaconf. the default value defined in H. If this variable does not exist, use it directly.
Default value defined by luaconf. h
Package. cpath: works the same way as packag. path, but it is used to load third-party C libraries. The initial value can be set through the Environment Variable lua_cpath.
Package. loadlib (libname, func): equivalent to manually opening the libname of the c library and exporting the function func to return, loadlib is actually ll_loadlib
2. Process of require:
Require (modelname)
The query order of require (which is the ll_require function in Lua) is as follows:
A. First, find modelname in package. Loaded. If this module already exists, return its value directly.
B. Find modelname in package. preload. If preload exists, use it as the loader and call loader (l)
C. according to package. find the modelname Of The Lua library in the path mode, which is defined by the module function. For the top-level Lua library, the file name is the same as the database name, and you do not need to call the module function explicitly in the Lua file (you can see the processing method in the ll_require function ), that is to say, Lua will directly complete the initialization process of a loader based on the Lua file.
D. according to package. cpath searches for the C library, which complies with some Lua specifications (export has function interfaces with certain characteristics). Lua has loaded the C library dynamically first, search for and call the interface with the corresponding name in the database, for example, luaopen_hello_world.
E. take the first ". "For segmentation, the module name is divided into :( main, sub) form, according to package. cpath searches for Main. If it exists, load the library and query the corresponding interface: luaopen_main_sub. For example, first query the hello library and query the luaopen_hello_world interface.
F. After obtaining the Loder, use modname as the unique parameter to call the loader function. Of course, the parameters are passed through the Lua stack, so the loader prototype must comply with Lua specifications: int lua_func (lua_state * l)
Ll_requireThe Return Value of the loader is assigned to the package. loaded [modelname]. If the loader does not return a package at the same time. when loaded [modelname] does not exist, ll_require will set the package. set loaded [modelname] to true. Finally, ll_reuqire returns package. Loaded [modelname] to the caller.
3. module processing process
Module (name, CB1, CB2 ,...)
A. If package. Loaded [name] is a table, use this table as a mod.
B. If the global variable name is a table, use this global variable as a mod.
C. create Table: t = {[name] = package. loaded [name], ["_ name"] = Name, ["_ m"] = T, ["_ package"] = * name * (Delete the last ". XXXX "part )}. if name is a string separated by vertices, the resulting mod looks like this:
Hello. World ==>{ ["hello"] = {["world"] ={ xxxxxxx }}}
D. Call CBS in sequence:
CB1 (MOD), CB2 (MOD ),...
E. Set the environment of the current module to mod, and set package. Loaded [name] = mod