lua基础语法
基础语法
最基础的
-- 两个破折号开始一行注释。
--[[
添加两个 [ 和 ] 可以使其成为
多行注释。
--]]
----------------------------------------------------
-- 1. 变量和流程控制。
----------------------------------------------------
num = 42 -- 数字可以是整数或浮点数。
s = 'walternate' -- 不可变字符串类似于 Python。
t = "双引号也可以"
u = [[ 双重括号
开始和结束
多行字符串。]]
t = nil -- 取消定义 t;Lua 有垃圾回收。
-- 块由 do/end 关键字表示:
while num < 50 do
num = num + 1 -- 没有 ++ 或 += 类型的运算符。
end
-- 如果子句:
if num > 40 then
print('超过 40')
elseif s ~= 'walternate' then -- ~= 代表不等于。
-- 等于检查是 ==,就像 Python;对字符串也可以。
io.write('不超过 40\n') -- 默认输出到 stdout。
else
-- 变量默认是全局的。
thisIsGlobal = 5 -- 驼峰命名法很常见。
-- 如何将变量设为局部:
local line = io.read() -- 读取下一个标准输入行。
-- 字符串连接使用 .. 运算符:
print('冬天来了,' .. line)
end
-- 未定义的变量返回 nil。
-- 这不是错误:
foo = anUnknownVariable -- 现在 foo = nil。
aBoolValue = false
-- 只有 nil 和 false 是虚假的;0 和 '' 是真的!
if not aBoolValue then print('它是假的') end
-- '或' 和 '与' 是短路运算。
-- 这类似于 C/js 中的 a?b:c 运算符:
ans = aBoolValue and 'yes' or 'no' --> 'no'
karlSum = 0
for i = 1, 100 do -- 范围包括两端。
karlSum = karlSum + i
end
-- 使用 "100, 1, -1" 作为范围进行倒计时:
fredSum = 0
for j = 100, 1, -1 do fredSum = fredSum + j end
-- 一般来说,范围是"开始,结束, 步长"。
-- 另一种循环结构:
repeat
print('未来之路')
num = num - 1
until num == 0
函数
function fib(n)
if n < 2 then return 1 end
return fib(n - 2) + fib(n - 1)
end
-- 闭包和匿名函数是可以的:
function adder(x)
-- 返回的函数是在 adder 被调用时创建的,
-- 并记住 x 的值:
return function (y) return x + y end
end
-- 返回函数
--[[
...
return function (y)
....
end
...
]]
a1 = adder(9)
a2 = adder(36)
print(a1(16)) --> 25
print(a2(64)) --> 100
-- 返回值、函数调用和赋值都可以处理
-- 可能长度不匹配的列表。
-- 不匹配的接收者是 nil;
-- 不匹配的发送者会被丢弃。
x, y, z = 1, 2, 3, 4
-- 现在 x = 1, y = 2, z = 3,4 被丢弃。
function bar(a, b, c)
print(a, b, c)
return 4, 8, 15, 16, 23, 42
end
x, y = bar('zaphod') --> 打印 "zaphod nil nil"
-- 现在 x = 4, y = 8,值 15...42 被丢弃。
-- 函数是第一类,可以是局部/全局的。
-- 这些是相同的:
function f(x) return x * x end
f = function (x) return x * x end
-- 这些也是相同的:
local function g(x) return math.sin(x) end
local g; g = function (x) return math.sin(x) end
-- 'local g' 声明使得 g 自引用是可以的。
-- 顺便说一句,三角函数以弧度为单位。
-- 只有一个字符串参数的调用不需要括号:
print 'hello' -- 正常工作。
表
-- 表 = Lua 唯一的复合数据结构;
-- 它们是关联数组。
-- 类似于 php 数组或 js 对象,它们是
-- 哈希查找字典,也可以用作列表。
-- 将表用作字典/映射:
-- 字典字面量默认具有字符串键:
t = {key1 = 'value1', key2 = false}
-- 字符串键可以使用类似 js 的点表示法:
print(t.key1) -- 打印 'value1'。
t.newKey = {} -- 添加一个新的键/值对。
t.key2 = nil -- 从表中删除 key2。
-- 任何(非 nil)值作为键的字面量表示法:
u = {['@!#'] = 'qbert', [{}] = 1729, [6.28] = 'tau'}
print(u[6.28]) -- 打印 "tau"
-- 对于数字和字符串,键匹配基本上是按值
-- 而对于表是按标识。
a = u['@!#'] -- 现在 a = 'qbert'。
b = u[{}] -- 我们可能期望 1729,但它是 nil:
-- b = nil,因为查找失败。查找失败是因为
-- 我们使用的键不是用于存储原始值的同一个对象。因此
-- 字符串和数字是更可移植的键。
-- 一个只有一个表参数的函数调用不需要括号:
function h(x) print(x.key1) end
h{key1 = 'Sonmi~451'} -- 打印 'Sonmi~451'。
for key, val in pairs(u) do -- 表迭代。
print(key, val)
end
-- _G 是一个特殊的所有全局变量的表。
print(_G['_G'] == _G) -- 打印 'true'。
-- 将表用作列表/数组:
-- 列表字面量隐式设置整数键:
v = {'value1', 'value2', 1.21, '吉瓦'}
for i = 1, #v do -- #v 是 v 的大小。
print(v[i]) -- 索引从 1 开始!!真疯狂!
end
-- '列表' 不是一个真实的类型。v 只是一个表
-- 具有连续的整数键,被视为一个列表。
元表和元方法
-- 一个表可以有一个元表,给表
-- 操作重载的行为。稍后我们将看到
-- 元表如何支持 js 原型行为。
f1 = {a = 1, b = 2} -- 表示分数 a/b。
f2 = {a = 2, b = 3}
-- 这将失败:
-- s = f1 + f2
metafraction = {}
function metafraction.__add(f1, f2)
sum = {}
sum.b = f1.b * f2.b
sum.a = f1.a * f2.b + f2.a * f1.b
return sum
end
setmetatable(f1, metafraction)
setmetatable(f2, metafraction)
s = f1 + f2 -- 在 f1 的元表上调用 __add(f1, f2)
-- f1 和 f2 没有其元表的键,不像
-- js 中的原型,因此您必须像这样检索它:
-- getmetatable(f1)。元表是一个普通的表
-- 具有 Lua 知道的键,例如 __add。
-- 但下一行失败,因为 s 没有元表:
-- t = s + s
-- 下面给出的类模式可以解决这个问题。
-- 元表上的 __index 重载点查找:
defaultFavs = {animal = 'gru', food = 'donuts'}
myFavs = {food = 'pizza'}
setmetatable(myFavs, {__index = defaultFavs})
eatenBy = myFavs.animal -- 成功!谢谢,元表
-- 直接的表查找失败将重试使用
-- 元表的 __index 值,这会递归进行。
-- __index 值也可以是一个函数(tbl, key)
-- 用于更自定义的查找。
-- __index,__add 等的值被称为元方法。
-- 完整列表。这里 a 是一个具有元方法的表。
-- __add(a, b) 用于 a + b
-- __sub(a, b) 用于 a - b
-- __mul(a, b) 用于 a * b
-- __div(a, b) 用于 a / b
-- __mod(a, b) 用于 a % b
-- __pow(a, b) 用于 a ^ b
-- __unm(a) 用于 -a
-- __concat(a, b) 用于 a .. b
-- __len(a) 用于 #a
-- __eq(a, b) 用于 a == b
-- __lt(a, b) 用于 a < b
-- __le(a, b) 用于 a <= b
-- __index(a, b) <fn 或一个表> 用于 a.b
-- __newindex(a, b, c) 用于 a.b = c
-- __call(a, ...) 用于 a(...)
类似类的表和继承
-- 类不是内置的;有不同的方法
-- 使用表和元表来创建它们。
-- 下面是此示例的解释。
Dog = {} -- 1.
function Dog:new() -- 2.
newObj = {sound = '汪'} -- 3.
self.__index = self -- 4.
return setmetatable(newObj, self) -- 5.
end
function Dog:makeSound() -- 6.
print('我说 ' .. self.sound)
end
mrDog = Dog:new() -- 7.
mrDog:makeSound() -- '我说汪' -- 8.
-- 1. Dog 充当类;它实际上是一个表。
-- 2. function tablename:fn(...) 与
-- function tablename.fn(self, ...)
-- 相同。: 会添加一个名为 self 的第一个参数。
-- 参见下面的 7 和 8 以了解 self 是如何获得其值的。
-- 3. newObj 将是 Dog 类的一个实例。
-- 4. self = 被实例化的类。通常
-- self = Dog,但继承可以改变它。
-- 当我们同时将 newObj 的元表和 self 的 __index 设置为 self 时,newObj 将获得 self 的函数。
-- 5. 提醒:setmetatable 返回其第一个参数。
-- 6. : 的用法与第 2 点相同,但这次我们期望
-- self 是一个实例而不是一个类。
-- 7. 与 Dog.new(Dog) 相同,因此 self = Dog 在 new() 中。
-- 8. 与 mrDog.makeSound(mrDog) 相同;self = mrDog。
----------------------------------------------------
-- 继承示例:
LoudDog = Dog:new() -- 1.
function LoudDog:makeSound()
s = self.sound .. ' ' -- 2.
print(s .. s .. s)
end
seymour = LoudDog:new() -- 3.
seymour:makeSound() -- '汪汪汪' -- 4.
-- 1. LoudDog 继承了 Dog 的方法和变量。
-- 2. self 拥有来自 new() 的 'sound' 键,见 3。
-- 3. 与 LoudDog.new(LoudDog) 相同,并转换为
-- Dog.new(LoudDog),因为 LoudDog 没有 'new' 键,
-- 但在其元表上有 __index = Dog。
-- 结果:seymour 的元表是 LoudDog,而
-- LoudDog.__index = LoudDog。因此 seymour.key 将
-- = seymour.key,LoudDog.key,Dog.key,取决于
-- 哪个表是第一个具有给定键的表。
-- 4. 'makeSound' 键在 LoudDog 中找到;这
-- 与 LoudDog.makeSound(seymour) 相同。
-- 如果需要,子类的 new() 类似于基类的:
function LoudDog:new()
newObj = {}
-- 设置 newObj
self.__index = self
return setmetatable(newObj, self)
end
模块
-- 假设文件 mod.lua 的内容如下:
local M = {}
local function sayMyName()
print('Hrunkner')
end
function M.sayHello()
print('你好啊')
sayMyName()
end
return M
-- 另一个文件可以使用 mod.lua 的功能:
local mod = require('mod') -- 运行文件 mod.lua。
-- require 是包含模块的标准方式。
-- require 的作用类似于: (如果没有缓存;见下文)
local mod = (function ()
<mod.lua 的内容>
end)()
-- 就像 mod.lua 是一个函数体,因此
-- mod.lua 内的局部变量在外部不可见。
-- 这有效,因为这里的 mod = mod.lua 中的 M:
mod.sayHello() -- 打印:你好啊 Hrunkner
-- 这是错误的;sayMyName 只存在于 mod.lua 中:
mod.sayMyName() -- 错误
-- require 的返回值是缓存的,因此一个文件
-- 最多只运行一次,即使多次 require。
-- 假设 mod2.lua 包含 "print('Hi!')"。
local a = require('mod2') -- 打印 Hi!
local b = require('mod2') -- 不打印;a=b。
-- dofile 类似于没有缓存的 require:
dofile('mod2.lua') --> Hi!
dofile('mod2.lua') --> Hi!(再次运行)
-- loadfile 加载一个 lua 文件,但尚未运行它。
f = loadfile('mod2.lua') -- 调用 f() 来运行它。
-- load 是用于字符串的 loadfile。
-- (loadstring 已被弃用,使用 load 代替)
g = load('print(343)') -- 返回一个函数。
g() -- 打印出 343;此时没有任何内容打印。
出处
Learn Lua in Y Minutes 使用GPT翻译的这个后来发现官网已经有官方的汉化版本!!!!大写的尴尬,而且这个站点还不止一种语言的教程