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