一、注释

单行注释:两个破折号
多行注释:[[ … ]]

二、变量和流程控制

所有的数字类型都是double

num=42

字符串是Immutable的,和python一样

s = 'walternate'
t = "double-quotes are also fine"
u = [[ Double brackets
          start and end
          multi-line strings.]]

lua有垃圾回收机制,t是undefined

t = nil

语句块用关键字do/end标示

while num < 50 do
    num = num + 1       
end

语句:
if num > 40 then
print('over 40')
elseif s ~= 'walternate' then – ~= 是不等号.
– 等号是== 对字符串也适用.
io.write('not over 40n') – 默认输出到stdout.
else
– 变量默认是全局的.
thisIsGlobal = 5 – 常用Camel样式.

– 局部变量如下定义:
local line = io.read() – 读取下一个stdin 行.

– 字符串连接使用 … 操作符:
print('Winter is coming, 'line)
end

未定义的变量返回nil
foo = anUnknownVariable – Now foo = nil.
aBoolValue = false
– 只有nil 和 false 是 falsy; 0 和 '' 是 true!
if not aBoolValue then print('twas false') end
– 'or' and 'and' 是短路的.

– 这和 C/js中的 a?b:c 相似:
ans = aBoolValue and 'yes' or 'no' –> 'no'

karlSum = <span class="number">0</span>
<span class="keyword">for</span> i = <span class="number">1</span>, <span class="number">100</span> <span class="built_in">do</span>  <span class="comment">-- 范围是闭区间.</span>
   karlSum = karlSum + i
<span class="function"><span class="keyword">end</span>

– 用 "100, 1, -1" 作为区间来递减:
fredSum = 0
for j = 100, 1, -1 do fredSum = fredSum + j end

– 总体上, 区间是 begin, end[, step].

– 另一种循环结构:
repeat
print('the way of the future')
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
a1 = adder(9)
a2 = adder(36)
print(a1(16)) –> 25
print(a2(64)) –> 100

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') –> prints "zaphod nil nil"
– 现在 x = 4, y = 8, 值 15…42 被丢弃了.

– 函数是一等公民, 可以是 local/global.
– 下面是等价的:
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

– 调用只有一个字符串的参数,不需要括号:
print 'hello' – Works fine.

四、表

Tables : 哈希查找的关联数组,和dictionaries、map类似,是lua仅有的复合数据结构。

Dict的的键默认是字符串的
t = {key1 = 'value1', key2 = false}
print(t.key1)  -- 输出 'value1'.
t.newKey = {}  -- 添加一个新的 key/value 对.
t.key2 = nil   -- 从table中移除 key2.

表常用的的键一般是数字或者字符串
u = {['@!#'] = 'qbert', [{}] = 1729, [6.28] = 'tau'}
print(u[6.28])  -- 输出"tau"
a = u['@!#']    -- a = 'qbert'.
b = u[{}]     -- 误认为是1729, 其实是 nil。

for key, val in pairs(u) do  -- 表迭代.
  print(key, val)
end

-- 调用一个 one-table-param 的函数不需要括号
function h(x) print(x.key1) end
h{key1 = 'Sonmi~451'}  -- Prints 'Sonmi~451'.

-- _G 是一个全局的特殊表.
print(_G['_G'] == _G)  -- 输出 'true'.

-- 把 tables 用作 lists / arrays:

-- List 的键默认是整数,键是连续的整数,其实还是table:
v = {'value1', 'value2', 1.21, 'gigawatts'}
for i = 1, #v do  -- #v 是列表v的长度.
  print(v[i])     -- 第一个索引是1
end

4.1. 元表和元方法.

–元表给予表操作符重载的特性,类似js的prototype的特性。

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

– 元表上的 __index 重载 . 查找:
defaultFavs = {animal = 'gru', food = 'donuts'}
myFavs = {food = 'pizza'}
setmetatable(myFavs, {__index = defaultFavs})
eatenBy = myFavs.animal – 可行! thanks, metatable

一个__index值也可以是个函数(tbl, key),有利于个性化查找。
像__index,add, … 都是元方法,下面是一个全表,这里 a是一个有metamethod的表

– __add(a, b) for a + b
– __sub(a, b) for a - b
– __mul(a, b) for a * b
– __div(a, b) for a / b
– __mod(a, b) for a % b
– __pow(a, b) for a ^ b
– __unm(a) for -a
– __concat(a, b) for a … b
– __len(a) for #a
– __eq(a, b) for a == b
– __lt(a, b) for a < b
– __le(a, b) for a <= b
– __index(a, b) <fn or a table> for a.b
– __newindex(a, b, c) for a.b = c
– __call(a, …) for a(…)

4.2. 类风格的表与继承

类不是内置的,有多种可以使用tables和metatables的方法

Dog = {}                                   -- 1.

function Dog:new() – 2.
newObj = {sound = 'woof'} – 3.
self.__index = self – 4.
return setmetatable(newObj, self) – 5.
end

function Dog:makeSound() – 6.
print('I say ' … self.sound)
end

mrDog = Dog:new() – 7.
mrDog:makeSound() – 'I say woof' – 8.

–1. Dog 像是一个class,它实际是一个表。

–2. 函数 tablename:fn(…) 和函数tablename.fn(self,…)一样,: 仅仅添加第一个名为self的参数。

–3. newObj是类Dog的实例。

–4. self就是被继承的类,但是继承可以改变self的值,这里是Dog,当我们设置newObj’s metatable 和 self’s __index to self时,newObj 才能使用self’s 函数。

–5. setmetatable 返回它的第一个参数

–6. 这时,self是一个实例而不是一个类。

–7. 和Dog.new(Dog)一样。

–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()  -- 'woof woof woof'      -- 4.

– 1. LoudDog 继承了 Dog’s 的方法和变量。

– 2. self 有一个来自于new()的 ‘sound’键。

– 3. 和LoudDog.new(LoudDog)一样, 由于LoudDog没有‘new’键,将被转换为 Dog.new(LoudDog),但是它的 metatable 拥有 index = Dog。
结论:seymour的 metatable是LoudDog,LoudDog.
index = LoudDog. 所以 seymour.key = seymour.key, LoudDog.key, Dog.key, 任何第一个含有给定键的表。

– 4. ‘makeSound’ key 包含在LoudDog;这和LoudDog.makeSound(seymour)一样.

– 如果有需要, 一个子类的 new() 可以和基类的一样:

function LoudDog:new()
  newObj = {}
  -- set up newObj
  self.__index = self
  return setmetatable(newObj, self)
end

五、模块

– 假设文件mod.lua 像如下所示:

local M = {}
local function sayMyName()
  print('Hrunkner')
end

function M.sayHello()
print('Why hello there')
sayMyName()
end

return M

– 另一个文件可以使用mod.lua's 的函数:
local mod = require('mod') – 运行文件 mod.lua.

– require 是 引用和包含 modules 的标准方法.
– require 其实像下面这样工作: (没有缓存的)
local mod = (function ()
<contents of mod.lua>
end)()
– mod.lua 像是一个函数体,所以 mod.lua内的局部变量对外不可见

– 因为在mod.lua里面,这里的mod = M :
mod.sayHello() – Says hello to Hrunkner.

– 错误; sayMyName 只存在于 mod.lua:
mod.sayMyName() – error

– 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! (runs it again)

– loadfile 装载一个lua 文件,但并不立即运行。
f = loadfile('mod2.lua') – 调用 f() 来运行.

– loadstring 相当于strings版的loadfile.
g = loadstring('print(343)') – 返回一个函数.
g() – 输出343; 此前无输出.

参考:

15分钟学会lua

Lua编程(Part 1):基本语法

Lua编程(Part 2):数据和标准库

Lua编程(Part 3):高级概念

Lua编程(Part 4):技巧

love 2D游戏引擎

lua官方学习文档

A quick tour of Torch internals

基于Torch的LSTM实现