『Programming in Lua 3』読書ノート(十一)

4507 ワード

日付:2014.7.11
Part Ⅱ Modules and Packages
モジュール(module)は、luaでもcでもない関数requireにロードできるコードであり、tableを作成して返す役割を果たす.このモジュールが出力する関数、定数などは、このtableで定義されており、その動作原理はネーミングスペースに似ています.
Luaのすべての標準ライブラリはモジュールで、使用方法:
e.g.
local  m = require "math"
print(m.sin(3.14))

Luaではモジュールをtableに格納したり、関数のパラメータとして使用したりすることができる.
require関数の制限は、ロードするモジュールにパラメータを渡すことができないことです.
モジュール自体は一度しかロードできません
The require Function
require関数loadモジュールを使用する場合、この関数はまずpackageから使用されます.loadedこのtableでモジュールがロードされているかどうかを確認します.モジュールの名前はmodnameと仮定します.
モジュールがロードされている場合は、ロードされた値が返されます.したがって、モジュールがロードされると、他のモジュールをロードする必要がある場合は、同じ値が返され、再ロードされません.
モジュールがロードされていない場合、そのモジュールの名前に基づいてLuaファイルが検索され、見つかったらloadfile関数でロードされ、loadfile関数のロードファイルは関数を返します.この関数をloaderと呼びます.
require関数がLuaファイルからモジュールが見つからない場合は、Cライブラリに移動します.Cライブラリで見つけた場合、この関数はpackageを使用します.loadlib、luaopenを呼び出すmodnameの関数はロードされません.このときのloaderはloadlibの実行結果であり、関数luaopen_modenameはlua関数を表します.
require関数は、2つのパラメータによってloaderを呼び出します.モジュールの名前とloaderを得るファイルの名前です.require関数はloaderが返す任意の値を返しpackageに格納する.loadedというtableでは,今後この同名モジュールへのロードはすべてこのtableから得られる.loaderが値を返さなかった場合、システムは後でモジュールを再ロードしないように、require関数はモジュールがtrueを返したと考えます.
ロードされたモジュールを強制的に再ロードしたい場合、最も簡単な方法はpackageからモジュールの値を再ロードすることです.loadedこのtableで消去:
これにより、次のモジュールをロードする必要がある場合に、再ロードされます.
Renaming a module
モジュールの名前を変更
一般的には、モジュールの元の名前でモジュールを使用しますが、名前の競合を防ぐために、モジュールの名前を変更する必要があります.モジュールのネーミングにはハイフンを使用します.Luaのrequire内部の操作関数は、モジュールの名前が次のように、ハイフンの後の名前を使用してモジュールのロードを自動的に操作します.
e.g.
m = require "v1-mod"

実は内部のluaopen_(ここではモジュール名)関数には、次の名前が使用されます.
luaopen_mod
Path searching
パス検索
requireの検索パスは、一般的な場合とは異なります.ANSI C(luaが実行するプラットフォーム)にはディレクトリという概念はありません.したがって、requireが使用するパスはテンプレートの列であり、各テンプレートはモジュール名をファイル名に変換する方法を指定します.具体的には、各テンプレートの下にあるrequireでは、これらの疑問符の代わりにモジュール名曲が使用され、要求に合致しているかどうかを検出します.
?;?.lua?c:\windows\?
--モジュール名がmodの場合、
mod;mod.lua;c\windows\mod
Luaコードのpathはpackageからです.パスで得られた
Cライブラリで検索に用いるpathはpackageからである.cpathで得られた.
関数package.searchpathは検索ライブラリの代わりに上記の様々なルールをカプセル化し、この関数は2つのパラメータを受け入れ、1つはモジュール名であり、1つは検索パスである.以上の検索ルールに従って検索作業を実行します.この関数の戻り値は、モジュールが存在する場合は存在する情報を返し、そうでない場合はnilにエラー情報を加えます.
e.g.
path = ".\\?.dll;C:\\ProgramFiles\\Lua502\\dll\\?.dll"
print(package.searchpath("X",path))
--    
nil    
     no file '.\X.dll'
     no file 'C:\ProgramFiles\Lua502\dll\X.dll'

Searchers
実際にrequire関数は、上述したよりも複雑です.ここでは概念searchersを引用する.1つのsearcherは、モジュール名をパラメータとして受け入れ、モジュールにloaderを返すか、モジュールが存在しない場合にnilを返す関数です.
package.searchersにはrequire関数に用いられるsearchersが列挙されている.requireはこれらのsearchersで探しています.
The Basic Approach for Wirting Modules in Lua
Luaにモジュールを書き込む方法
最も簡単な方法は、tableを新しく作成し、使用する関数をtableに格納し、このtableに戻ることです.
モジュールを簡単に実装:
local M = {}

function M.new(r,i) return {r = r,i = i} end
--define constant "i"
M.i = M.new(0,1)

function M.add(c1,c2)
     return M.new(c1.r + c2.r,c1.i + c2.i)
end

function M.sub(c1,c2)
     return M.new(c1.r - c2.r,c1.i -c2.i)
end

function M.mul(c1,c2)
     return M.new(c1.r*c2.r - c1.i*c2.i,c1.r*c2.i + c1.i*c2.r)
end

local function inv(c)
     local n = c.r^2 +c.i^2
     return M.new(c.r/n,-c.i/n)
end

function M.div(c1,c2)
     return M.mul(c1,inv(c2))
end

function M.tostring(c)
     return "(" .. c.r .. "," .. c.i .. ")"
end

return M           --    

--実はよくわかりません...
Using Environment
モジュール内で環境を変更することで、グローバル環境への影響を回避します.
自分のモジュールで変更した場合に注意してください.ENVの場合、残りのモジュールに影響を与えるため、変更しています.ENVの前にいくつかの処理が必要です.
e.g.
local M = {}
setmetatabel(M,{__index = _G})
_ENV = M 

この場合、Mモジュールにはすべてのグローバル変数が含まれます.
or
local M = {}
local _G = _G
_ENV = M

この方法では、グローバル変数を使用するときに接頭辞を付けます.G,この方式はメタメソッドの使用に関与していないため,より速い運転速度をもたらす.
もう1つの方法は、モジュールで使用する関数をローカルに定義することです.
e.g.
local M = {}

--ローカル変数として定義
local sqrt = math.sqrt
local io = io
_ENV = nil

この方式は、より速い運転速度をもたらすこともできます.
Submodules and Packages
サブモジュール
Luaは、モジュールの階層化を実現するために句点記号を使用することを可能にする.例えば、モジュールmod.subはmodモジュールのサブモジュールである.パッケージはモジュールのツリーです.
reuqire関数は検索時に、句点記号を一定に変換します-システムディレクトリ区切り記号を使用します(UNIXでは「/」、windowsでは「」を使用します)
 
転載先:https://www.cnblogs.com/zhong-dev/p/4044575.html