lua学习

lua基础

一、注释

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

二、变量和流程控制

所有的数字类型都是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 语句:
    if num > 40 then
          print('over 40')
    elseif s ~= 'walternate' then  -- ~= 是不等号.
-- 等号是== 对字符串也适用.
      io.write('not over 40\n')  -- 默认输出到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 = 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

-- 总体上, 区间是 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实现