Module and implementation guide in Lua

Time:2022-5-20

From the perspective of use, a module is a program library, which can be loaded through the requirements provided by Lua itself. Then you get a global variable that represents a table. This table is like a namespace. Its content is everything exported by the module, such as functions and constants. Simply put, the module in Lua is a table, which can include anything. This paper first introduces the module related require function in detail, including the execution process of the function and the path to find the module, then introduces three methods to realize the module, and gives the corresponding advantages and disadvantages.

Require function

This function is used to load a module, that is, find the module to be loaded according to the specified path and the passed in parameters. The function prototype is as follows:

      require (modname)

The execution process of this function is as follows:

1. Lookup table package Loaded to see if modname has been loaded. If yes, the require function directly returns package Loaded [modname], otherwise continue to execute and find the loader of the module.

2. To find the loader, require uses the array package Searchers (introduced by Lua 5.2 and called package.loaders in the previous version. In essence, the two are just different names). Each element in the array is a function.

The first function is used to search the table package Preload, if any, returns the corresponding loader.

The second function is used to obtain the loader of lua module, and its search path is stored in package In path, it is a string, for example:

 

Copy codeThe code is as follows:

/usr/local/share/lua/5.2/?.lua;/usr/local/share/lua/5.2/?/init.lua;/usr/local/lib/lua/5.2/?.lua;/usr/local/lib/lua/5.2/?/init.lua;./?.lua 

 

Will replace each “?” with the module name, Then, whether such a file exists is detected according to the result of replacement. This work is done through the function package Searchpath. package. The prototype of searchpath function is as follows:
      package.searchpath (name, path [, sep [, rep]])

The parameter path is the string to be searched, separated by semicolons; Name is the file to find; The parameter SEP (the default value is. “”) can be used in name and replaced with rep (the default value is the separator of the system directory) during the search. For example, path is

 

Copy codeThe code is as follows:

“./?.lua;./?.lc;/usr/local/?/init.lua”

 

To find foo a. Will try to find the file

 

Copy codeThe code is as follows:

./foo/a.lua, ./ Foo / a.lc, and / usr / local / foo / A / init lua 

 

That is, Lua supports hierarchical module names.
The third function is used to obtain the loader of C module, and its search path is stored in package Cpath is also a string, for example:

 

Copy codeThe code is as follows:

/usr/local/lib/lua/5.2/?.so;/usr/local/lib/lua/5.2/loadall.so;./?.so 

 

Each “?” will also be replaced with the module name, Then, whether such a file exists is detected according to the result of replacement. This work is also done through the function package Searchpath.
The fourth function is to use the all in one loader. Using this function, a package can contain multiple C sub modules. In addition to the first, the other three return the file name found as an additional value in addition to the loader.

3. After finding the loader, require will call the loader with two parameters, one is the passed in parameter modname, and the other is the returned extra value. If the loader returns a value other than nil, assign this value to package loaded[modname]。 If the load returns a nil and the loader executes the package If loaded [modname] is still empty, package Loaded [modname] is assigned to true. In either case, require will return package loaded[modname]。 If there is a task error in this process, the require function generates an error to the caller.

Finally, with regard to the require function, it is worth noting that:

1. If require finds a Lua file, load the code through LoadFile. If it finds a C library, load it through loadlib. Note that both LoadFile and loadlib essentially load code and do not run them. To run them, require calls the code with the module name as a parameter.

2. To force require to load the same library twice, simply delete package The module entry in loaded, that is, assign the corresponding entry as nil.

3. Through the above analysis of the loading process, we know that to load your own Lua file or C library, you can modify package Path or package Cpath value, load the path to search.

4. You can also define your own loading functions (in addition to the existing loadlib and LoadFile), such as loading zip files or even downloading a file from the web.

Method of writing module

One method: for lua5 For 0 and 5.1, the easiest way to write a module is to use the module function provided by Lua itself (note that it has been deleted in Lua 5.2), such as writing a module Foo and a module file foo_ file. Lua is as follows:

 

Copy codeThe code is as follows:

module(“foo”, package.seeall) 
function test() 
end 

 

Use this module in other files as follows:

 

Copy codeThe code is as follows:

require(“foo_file.lua”) 
foo.test() 

 

After the require is executed, the module foo will be a variable of the global environment, which can also be used in other places. The prototype of module function is as follows:

 

Copy codeThe code is as follows:

module (name [, ···]) 

 

Module will check the package before creating the module table Whether the loaded module has been included, or whether a variable with the same name as the module already exists. If the table is found, it will reuse the table as a module. In other words, you can use module to open a created module.

For the module function, there are the following problems, such as in the module file module0_ Test includes:

 

Copy codeThe code is as follows:

module(“mymodule”, package.seeall)                                                                      
function foo() 
    print(“Hello World!”) 
end 

 

This module can be used in another file as follows:

 

Copy codeThe code is as follows:

require “module0_test” 
mymodule.foo()             –Hello World! 
mymodule.print(“example”)  –example 

 

The second call does not report an error, and it is very strange. At this time, because the module mechanism is a member that cannot be found in the module, go to_ G global variable lookup is implemented in the following way:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
do
  local globaltbl = _G
  local newenv = setmetatable({}, {
    __index = function (t, k)
      local v = t[k]
      if v == nil then return globaltbl[k] end
      return v
    end,
    __newindex = M,
  })
  if setfenv then
    setfenv(1, newenv) -- for 5.1
  else
    _ENV = newenv -- for 5.2
  end
end

If a member cannot be found in the module_ G, and such access is also very inefficient, because members are accessed through a meta table.

Method 2: the basic idea of this method is to let the main program of the module have an exclusive environment, so that all functions or variables share this table, and all global variables are recorded in this table. Of course, local variables will not. The code snippet is as follows:

?
1
2
3
4
5
6
7
8
9
local modename = ...
local M = {}
_G[modename] = M
package.loaded[modname] = M
if setfenv then
  setfenv(1, newenv) -- for 5.1
else
  _ENV = newenv -- for 5.2
end

If so, access in the module_ For example, if you need to prefix a variable in G_ G.print。 In order to solve this problem, there are several methods, each with advantages and disadvantages:

1. After setting the meta table of M, i.e. setmetable (m, {_index = _g}), access to global variables must pass through the meta table, which is expensive.

2. Set local_ G = _ G. After doing so, access to global variables still need to be prefixed, but it is faster.

3. Set the global variables required by the module as local variables, such as local IO = io. This will be cumbersome, but the fastest.

Method 3: it is also the concept of using environment. For example, the module files are as follows:

 

Copy codeThe code is as follows:

function foo()                                                                                          
    print(“Hello World!”)                                                                               
end 

 

In order to use it, the method is as follows:

?
1
2
3
4
5
6
7
8
9
10
11
local function Import(filename)                                    
  f = loadfile(filename)                                       
  local M = {}                                            
  setmetatable(M, {__index = _G})                                  
  setfenv(f,M)()
  return M
end
 
local FOO = Import("module2_test.lua")
 
FOO.foo() --output “Hello World!”

In this way, you only need to call the import method, and its return value is the module. This method places the module related access work in the place of the module you use.

The above is the whole content of this article. I hope it can help you learn Lua.

Recommended Today

Modul of fastems

Each module of fastems is implemented from the abstract class Fastems.Mms.Client.Infrastructure.UiModuleBase; public class DataManagerModule : UiModuleBase { public override void Initialize() { AddResourceDictionary(“/Resources/DataManagerResources.xaml”, typeof(DataManagerModule)); RegisterViewWithRegion(“DialogRegion”, typeof(DialogView)); RegisterViewWithRegion(“BusyIndicatorRegion”, typeof(BusyIndicatorView)); } } And Fastems.Mms.Client.Infrastructure.UiModuleBase inherits from Fastems.Mms.Client.Infrastructure.ModuleBase public abstract class UiModuleBase : ModuleBase { [Import] public IRegionManager RegionManager { get; set; } [Import] public IMergedDictionaryRegistry MergedDictionaryRegistry { […]