11.模块与多脚本

11.模块与多脚本


11.1 知识点

全局变量和局部变量

全局变量

-- 直接 变量 = 值 声明的变量都是全局变量
a = 1
b = "123"

-- Lua 中的循环体内,如果也是 变量 = 值 这样赋值,也是全局变量
-- 循环体外也能使用
for i = 1, 2 do
    c = "韬老狮" -- 循环体内全局变量赋值
end

print(c) -- 韬老狮,循环体外可以得到循环体内的全局变量赋值

全局变量不是不能用,但项目里一般不建议乱用。
尤其是多脚本之后,一个脚本里随手写出来的全局变量,其他脚本也能访问到,很容易造成命名冲突和状态污染。

局部变量

-- 局部变量的关键字 local
-- 通过 local 变量 = 值 声明局部变量
for i = 1, 2 do
    local d = "韬老狮"
    print("循环中的d" .. d) -- 循环中的d韬老狮,循环体内可以使用局部变量
end

print(d) -- nil,循环体外不能使用局部变量

fun = function()
    local tt = "123123123" -- 函数中加了 local,就是局部变量
end

fun()
print(tt) -- nil,函数中的 tt 加了 local,外部访问不到

local tt2 = "555"
print(tt2) -- 555,刚声明的局部变量当然可以使用

写 Lua 脚本时,能写 local 的地方尽量写 local。这个习惯很重要,特别是以后脚本多了之后,不然全局变量会越来越乱。

执行多脚本

声明一个LuaMultiScriptTest.lua脚本

print("我是LuaMultiScriptTest脚本")

GlobalVariable = "我是全局变量"
print("在LuaMultiScriptTest脚本打印的:" .. GlobalVariable)

local LocalAVariable = "我是局部变量"
print("在LuaMultiScriptTest脚本打印的:" .. LocalAVariable)

-- 可以在脚本最后返回一个外部希望获取的内容
-- 比如返回一个局部变量,给外部得到
return LocalAVariable

多脚本执行关键字 require 用于执行并加载指定脚本

  • 多脚本执行关键字 require,传入脚本名,用双引号或单引号包裹。
  • require 后会执行并加载传入的脚本。
  • 写法:
require("脚本名")
require('脚本名')
  • 注意:学习阶段脚本名尽量不要用中文。
  • 执行的脚本要能被 Lua 的搜索路径找到。最简单的情况,就是和当前脚本在同一目录下。
require('LuaMultiScriptTest') -- 执行 LuaMultiScriptTest 这个测试 Lua 多脚本的脚本
-- 我是LuaMultiScriptTest脚本
-- 在LuaMultiScriptTest脚本打印的:我是全局变量
-- 在LuaMultiScriptTest脚本打印的:我是局部变量

print(GlobalVariable) -- 我是全局变量,LuaMultiScriptTest 脚本的全局变量能被当前脚本使用
print(LocalAVariable) -- nil,LuaMultiScriptTest 脚本的局部变量不能被当前脚本使用

-- 如果脚本已经被 require 加载执行过,再 require 一次不会重复执行
require("LuaMultiScriptTest")

-- require 执行一个脚本时,可以在脚本最后返回一个外部希望获取的内容
-- 比如返回一个局部变量,用一个变量来接

-- 由于 LuaMultiScriptTest 已经加载过一次,这里先卸载 LuaMultiScriptTest
package.loaded["LuaMultiScriptTest"] = nil

-- 再重新加载 LuaMultiScriptTest
local testLA = require("LuaMultiScriptTest")
-- 我是LuaMultiScriptTest脚本
-- 在LuaMultiScriptTest脚本打印的:我是全局变量
-- 在LuaMultiScriptTest脚本打印的:我是局部变量

print(testLA) -- 我是局部变量

这里要注意一个点:require 不是单纯“执行文件”这么简单。它会把加载结果缓存到 package.loaded 里。
所以同一个脚本已经加载过之后,再次 require 默认不会重新执行脚本内容,而是直接返回缓存结果。

package.path 简单理解

  • require 不是凭空找到脚本的,而是按照 package.path 里的搜索路径去查找。
  • 学习阶段可以先简单理解成:“当前目录 + Lua 默认搜索路径”。
  • 项目里 require 的加载路径可能会被框架或者自定义 Loader 接管,比如 Unity Lua 热更项目里就经常不会直接使用原生文件路径。
print(package.path)

package.path 里通常会有类似 ?.lua?/init.lua 这样的规则。
这里的 ? 可以先理解成脚本名占位符。比如:

require("LuaMultiScriptTest")

Lua 会根据 package.path 里的规则,尝试去找对应的 LuaMultiScriptTest.lua
基础阶段不需要把搜索规则背得很细,先知道 require 是按路径规则找脚本的就行。

卸载多脚本

  • package.loaded["脚本名"] 里保存的是该脚本的加载结果。
  • 如果脚本没有显式 return,通常会缓存为 true
  • 如果脚本最后 return 了一个值,就会缓存这个返回值。
  • package.loaded["脚本名"] = nil 可以把已经加载过的脚本从缓存里移除。
  • 移除之后,再次 require 这个脚本时,就会重新加载执行。
print(package.loaded["LuaMultiScriptTest"]) -- 如果脚本最后 return 了局部变量,这里打印的就是返回值

-- package.loaded["脚本名"] = nil 卸载已经执行过的脚本
package.loaded["LuaMultiScriptTest"] = nil

print(package.loaded["LuaMultiScriptTest"]) -- nil

-- 可以重新加载 LuaMultiScriptTest 了
require("LuaMultiScriptTest")
-- 我是LuaMultiScriptTest脚本
-- 在LuaMultiScriptTest脚本打印的:我是全局变量
-- 在LuaMultiScriptTest脚本打印的:我是局部变量

这只是基础用法。后面如果涉及热重载,不能只靠 package.loaded[name] = nil 就认为万事大吉。旧引用、旧对象、旧回调这些问题会复杂很多,放到 Lua 进阶知识里再整理。

大G表

  • _G 表是一个全局表,它保存了全局环境中的变量。
  • 直接声明的全局变量,会放到 _G 里。
  • 加了 local 的局部变量,不会放到 _G 表中。
for k, v in pairs(_G) do
    print(k, v)
    -- a	1
    -- string	table: 00B49FE8
    -- xpcall	function: 00B479D0
    -- b	123
    -- package	table: 00B48050
    -- tostring	function: 00B47950
    -- print	function: 00B47590
    -- os	table: 00B4A038
    -- ...
end

-- 局部变量,加了 local 的变量,不会存到 _G 表中

实际项目里,少写全局变量本质上也是在减少 _G 表里的污染。
脚本少的时候看不出来,脚本一多,全局变量命名冲突就很难排查。


11.2 知识点代码

Lesson11_模块与多脚本.lua

print("**********模块与多脚本************")

print("**********知识点一 全局变量和局部变量************")

-- 全局变量
-- 直接 变量 = 值 声明的变量都是全局变量
a = 1
b = "123"

-- Lua 中的循环体内,如果也是 变量 = 值 这样赋值,也是全局变量
-- 循环体外也能使用
for i = 1, 2 do
    c = "韬老狮" -- 循环体内全局变量赋值
end

print(c) -- 韬老狮,循环体外可以得到循环体内的全局变量赋值

-- 全局变量不是不能用,但项目里一般不建议乱用
-- 脚本多了以后,全局变量很容易造成命名冲突和状态污染

-- 局部变量
-- 局部变量的关键字 local
-- 通过 local 变量 = 值 声明局部变量
for i = 1, 2 do
    local d = "韬老狮"
    print("循环中的d" .. d) -- 循环中的d韬老狮,循环体内可以使用局部变量
end

print(d) -- nil,循环体外不能使用局部变量

fun = function()
    local tt = "123123123" -- 函数中加了 local,就是局部变量
end

fun()
print(tt) -- nil,函数中的 tt 加了 local,外部访问不到

local tt2 = "555"
print(tt2) -- 555,刚声明的局部变量当然可以使用


print("**********知识点二 执行多脚本************")

-- 多脚本执行关键字 require,传入脚本名,用双引号或单引号包裹
-- require 后会执行并加载传入的脚本
-- require("脚本名")
-- require('脚本名')
-- 注意:学习阶段脚本名尽量不要用中文
-- 执行的脚本要能被 Lua 的搜索路径找到,最简单的情况是和当前脚本在同一目录下

require('LuaMultiScriptTest') -- 执行 LuaMultiScriptTest 这个测试 Lua 多脚本的脚本
-- 我是LuaMultiScriptTest脚本
-- 在LuaMultiScriptTest脚本打印的:我是全局变量
-- 在LuaMultiScriptTest脚本打印的:我是局部变量

print(GlobalVariable) -- 我是全局变量,LuaMultiScriptTest 脚本的全局变量能被当前脚本使用
print(LocalAVariable) -- nil,LuaMultiScriptTest 脚本的局部变量不能被当前脚本使用

-- 如果脚本已经被 require 加载执行过,再 require 一次不会重复执行
require("LuaMultiScriptTest")

-- require 执行一个脚本时,可以在脚本最后返回一个外部希望获取的内容
-- 比如返回一个局部变量,用一个变量来接

-- 由于 LuaMultiScriptTest 已经加载过一次,这里先卸载 LuaMultiScriptTest
package.loaded["LuaMultiScriptTest"] = nil

-- 再重新加载 LuaMultiScriptTest
local testLA = require("LuaMultiScriptTest")
-- 我是LuaMultiScriptTest脚本
-- 在LuaMultiScriptTest脚本打印的:我是全局变量
-- 在LuaMultiScriptTest脚本打印的:我是局部变量

print(testLA) -- 我是局部变量


print("**********知识点三 package.path 简单理解************")

-- require 不是凭空找到脚本的
-- 它会按照 package.path 里的搜索路径去查找
-- 学习阶段可以先理解成:当前目录 + Lua 默认搜索路径
-- 项目里 require 的加载路径可能会被框架或者自定义 Loader 接管

print(package.path)

-- package.path 里通常会有类似 ?.lua、?/init.lua 这样的规则
-- 这里的 ? 可以先理解成脚本名占位符
-- 比如 require("LuaMultiScriptTest") 时
-- Lua 会根据 package.path 里的规则,尝试去找 LuaMultiScriptTest.lua


print("**********知识点四 卸载多脚本************")

-- package.loaded["脚本名"] 里保存的是该脚本的加载结果
-- 如果脚本没有显式 return,通常会缓存为 true
-- 如果脚本最后 return 了一个值,就会缓存这个返回值

print(package.loaded["LuaMultiScriptTest"]) -- 如果脚本最后 return 了局部变量,这里打印的就是返回值

-- package.loaded["脚本名"] = nil 可以把已经加载过的脚本从缓存里移除
package.loaded["LuaMultiScriptTest"] = nil

print(package.loaded["LuaMultiScriptTest"]) -- nil

-- 移除之后,再次 require 这个脚本时,就会重新加载执行
require("LuaMultiScriptTest")
-- 我是LuaMultiScriptTest脚本
-- 在LuaMultiScriptTest脚本打印的:我是全局变量
-- 在LuaMultiScriptTest脚本打印的:我是局部变量


print("**********知识点五 大G表************")

-- _G 表是一个全局表,它保存了全局环境中的变量
-- 直接声明的全局变量,会放到 _G 里
-- 加了 local 的局部变量,不会放到 _G 表中

for k, v in pairs(_G) do
    print(k, v)
    -- a	1
    -- string	table: 00B49FE8
    -- xpcall	function: 00B479D0
    -- b	123
    -- package	table: 00B48050
    -- tostring	function: 00B47950
    -- print	function: 00B47590
    -- os	table: 00B4A038
    -- ...
end

-- 局部变量,加了 local 的变量,不会存到 _G 表中

LuaMultiScriptTest.lua

print("我是LuaMultiScriptTest脚本")

GlobalVariable = "我是全局变量"
print("在LuaMultiScriptTest脚本打印的:" .. GlobalVariable)

local LocalAVariable = "我是局部变量"
print("在LuaMultiScriptTest脚本打印的:" .. LocalAVariable)

-- 可以在脚本最后返回一个外部希望获取的内容
-- 比如返回一个局部变量,给外部得到
return LocalAVariable


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com

×

喜欢就点赞,疼爱就打赏