chapter15 Modules and Packages-01

Starting in version 5.1, Lua has defined a set of policies for modules and packages
(a package being a collection of modules). These policies do not demand any
extra facility from the language () ;
也就是不需要Lua再提供其他的特性去实现module and package, 用我们以前学到的就可以实现了
 programmers can implement them using what
we have seen so far: tables, functions, metatables, and environments. Programmers
are free to use different policies.  看下去就知道其实真没什么其他新的东西去implement module

From the point of view of the user, a module is some code (either in Lua or
in C) that can be loaded through require and that creates and returns a table. just a table 而已

Everything that the module exports, such as functions and constants, it defines
inside this table, which works as a namespace.


As an example, all standard libraries are modules. You can use the mathematical
library like this:
local m = require "math"
print(m.sin(3.14))

However, the stand-alone interpreter preloads all standard libraries with code
equivalent to this:
math = require "math"
string = require "string"
.....

An obvious benefit of using tables to implement modules is that we can
manipulate modules like any other table and use the whole power of Lua to
create extra facilities. In most languages, modules are not first-class values
(that is, they cannot be stored in variables, passed as arguments to functions,
etc.),
so those languages need special mechanisms for each extra facility they
want to offer for modules. In Lua, you get extra facilities for free. 确实是,Lua 使用
module 就是个普通的table,可以作为变量来存储,可以传给函数 (that's module is first class value),,
但类似C++ dll, 是不行的,需要系统提供facilities to run th
e dll

For instance, there are several ways for a user to call a function from a
module. The usual way is this:
local mod = require "mod"
mod.foo()
The user can set any local name for the module:
local m = require "mod"
m.foo()


She can also provide alternative names for individual functions:
local m = require "mod"
local f = mod.foo
f()



A common complaint against require is that it cannot pass arguments to the
module being loaded. For instance, the mathematical module might have an
option for choosing between degrees and radians:
-- bad code
local math = require("math", "degree")  不可以这样写的,,,

The problem here is that one of the main goals of require is to avoid loading a
module multiple times
. Once a module is loaded, it will be reused by whatever
part of the program that requires it again. There would be a conflict if the same
module were required with different parameters:
-- bad code
local math = require("math", "degree")
-- somewhere else in the same program
local math = require("math", "radians")


In case you really want your module to have parameters, it is better to create
an explicit function to set them, like here:
local mod = require"mod"
mod.init(0, 0)  --解决方法


If the initialization function returns the module itself, we can write that code
like this:
local mod = require"mod".init(0, 0) --require return table as module, then call this table's init method
Another option is to make the module returns its initialization function, and
only that function returns the module table:
local mod = require"mod"(0, 0) --require return a function, and that function return a module table

In any way, remember that the module itself is loaded only once; it is up to the
module to handle conflicting initializations
.


15.1 The require Function
For require, a module is just any code that defines some values (such
as functions or tables containing functions). Typically, that code returns a table
comprising the module functions. However, because this action is done by the
module code, not by require, some modules may choose to return other values
or even to have side effects
. 就象上面的那样,返回一个初始化函数,然后由这个函数返回module

To load a module, we simply call require"modname". The first step of
require is to check in table package.loaded whether the module is already
loaded. If so, require returns its corresponding value. Therefore, once a module
is loaded, other calls requiring the same module simply return the same value,
without running any code again.

If the module is not loaded yet, require searches for a Lua file with the
module name. If it finds a Lua file, it loads it with loadfile. The result of that
is a function that we call a loader. (The loader is a function that, when called,
loads the module.)

果然是没什么新的东西, f=loadfile(PATH_SERACH); f();// 这样 model 里面的东西就load进来了

If require cannot find a Lua file with the module name, it searches for
a C library with the module name. If it finds a C library, it loads it with
package.loadlib (which we discussed in Section 8.3), looking for a function
called luaopen_modname. The loader in this case is the result of loadlib, that
is, the function luaopen_modname represented as a Lua function
.

No matter whether the module was found in a Lua file or a C library, require
now has a loader for it. To finally load the module, require calls the loader
with two arguments: the module name and the name of the file where it got
the loader. (Most modules just ignore these arguments.) If the loader returns
any value, require returns this value and stores it in the package.loaded table
to return the same value in future calls for this same module. If the loader
returns no value, require behaves as if the module returned true. Without this

correction, a subsequent call to require would run the module again.


find in  .lua file, call loadfile return a loader

find  in .C file, call package.loadlib return a loadlib .

then put in to package.loaded. eventhoug not found will also updata package.loaded,

   correction, a subsequent call to require would run the module again.Without this




To force require into loading the same module twice, we simply erase the
library entry from package.loaded:
package.loaded.<modname> = nil  will reload again when call again

Renaming a module
Usually, we use modules with their original names, but sometimes we must
rename a module to avoid name clashes. A typical situation is when we need to
load different versions of the same module, for instance for testing. Lua modules
do not have their names fixed internally, 1.so usually it is enough to rename the
.lua file.
However, we cannot edit a binary library to correct the name of its
luaopen_* function. To allow for such renamings, require uses a small trick: if
the module name contains a hyphen, require strips from the name its prefix up
to the hyphen when creating the luaopen_* function name.
For instance, if a
module is named a-b, require expects its open function to be named luaopen_b,
instead of luaopen_a-b
(which would not be a valid C name anyway). So, if we
need to use two modules named mod, we can rename one of them to v1-mod, for
instance. When we call m1=require"v1-mod", require will find the renamed file

v1-mod and, inside this file, the function with the original name luaopen_mod. 

(need go back when I know how to use and     write a C module)



Path searching
When searching for a Lua file, require uses a path that is a little different from
typical paths. The typical path is a list of directories wherein to search for
a given file. However, ANSI C (the abstract platform where Lua runs) does
not have the concept of directories.(也就是not a real path, or 我们可以说是template path.由这个template 构造real path)
 Therefore, the path used by require is
a list of templates, each of them specifying an alternative way to transform a
module name (the argument to require) into a file name. More specifically, each
template in the path is a file name containing optional question marks.
For each
template, require replaces the module name for each ‘?’ and checks whether
there is a file with the resulting name; if not, it goes to the next template. The
templates in a path are separated by semicolons (a character seldom used for
file names in most operating systems). For instance, if the path is

?;?.lua;c:\windows\?;/usr/local/lua/?/?.lua
then the call require"sql" will try to open the following Lua files:
sql
sql.lua
c:\windows\sql
/usr/local/lua/sql/sql.lua

=================
> =package.path
C:\Trevor\lua\bin\lua\?.lua;C:\Trevor\lua\bin\lua\?\init.lua;C:\Trevor\lua\bin\?
.lua;C:\Trevor\lua\bin\?\init.lua;.\?.lua
==================
The path that require uses to search for Lua files is always the current value
of variable package.path. When Lua starts, it initializes this variable with the
value of the environment variable LUA_PATH_5_2. If this environment variable
is not defined, Lua tries the environment variable LUA_PATH. If both are not
defined, Lua uses a compiled-defined default path. (In Lua 5.2, the command-line
option -E prevents the use of those environment variables and
forces the default.)
When using the value of an environment variable,
Lua substitutes the default path for any substring “;;”.
For instance, if you set LUA_PATH_5_2 to “mydir/?.lua;;”, the final path will be
the template “mydir/?.lua” followed by the default path.

The path used to search for a C library works exactly in the same way,
but its value comes from variable package.cpath (instead of package.path).

Similarly, this variable gets its initial value from the environment variables
LUA_CPATH_5_2 or LUA_CPATH. A typical value for this path in UNIX is like this:
./?.so;/usr/local/lib/lua/5.2/?.so


Note that the path defines the file extension. The previous example uses .so for
all templates; in Windows, a typical path would be more like this one:
.\?.dll;C:\Program Files\Lua502\dll\?.dll


> =package.cpath
C:\Trevor\lua\bin\?.dll;C:\Trevor\lua\bin\loadall.dll;.\?.dll



Function package.searchpath encodes all those rules for searching libraries.
It receives a module name and a path, and looks for a file following the rules
described here. It returns either the name of the first file that exists or nil plus
an error message describing all files it unsuccessfully tried to open, as in the
next example:
> path = ".\\?.dll;C:\\Program Files\\Lua502\\dll\\?.dll"
> print(package.searchpath("X", path))
nil
no file '.\X.dll'

no file 'C:\Program Files\Lua502\dll\X.dll'


 =package.searchpath("lession14",package.path)
C:\Trevor\lua\bin\lession14.lua


will continue in next blog






  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值