游戏里面用lua来热更新的
redis的默认方法也是lua(我觉得是因为和nosql很搭)

变量

  1. 全局变量直接使用的时候为nil
  2. 数组下标从0开始(不推荐)a = {[0]="123","32","23"};
  3. 支持多返回值,多个同时赋值,只需要一个时候使用哑元_
  4. 尽量避免一个下划线开头+大写字母
  5. ---[[可以注销掉块注释
  6. type函数永远返回一个字符串
  7. lua将falsenil视为假,将0和空字符串视为真
  8. LUA对于小于1014的数字用双精度没有四舍五入的浮点误差,合法的数字写法:4,0.4,4.58e-3,0.3e12,5e+20
  9. Lua的字符串是只读的,\<ddd>表达数值转义,[[ ]],[===[ ]===]界定换行字符串,(类似的界定注释)
  10. tonumber, tostring不成功返回nil
  11. #a获取字符串a的长度,table.maxn对于nil更加安全
  12. table永远是匿名的,a ={},b=ab保持了一个对于a所指向table的引用
  13. a.xa["x"]是一样的,点作为记录,key暗示任意字符串
  14. x - x%1取整
  15. x,y=y,x交换
  16. do end构成基本块(local)

I/O

1
2
a = io.read("*number")
print(a)

function

notes

  1. 如果要在函数中间使用return,需要加do return end
  2. 可变参数(...), 获取arg
  3. 尾调用不保留调用者栈,这种情况下不会栈溢出, goto(用来编写状态机)
  4. 若将函数返回值作为不是最后一个的表达式,保留第一个返回值
  5. 如果函数调用在单独的一个圆括号里面,只能返回一个结果
  6. 函数名只是持有某个函数的变量
  7. 函数内部变量是一个closure,相当于对象的private variable

example

1
2
3
4
5
6
7
8
9
10
11
12
function foo(x) return 2 * x end
==
foo = function (x) return 2 * x end


--
function derivative(f, delta)
delta = delta or 1e-4
return function(x)
return (f(x+delta) - f(x))/delta
end
end

sort

1
table.sort(tb, function(a,b) return (a.name > b.name) end

3-var

1
2
3
-- 对于and来说第一个操作数为真,返回第二个操作数
-- or第一个操作数为假,返回第二个操作数
(a and b) or c -- a ? b : c, b不可以为false

unnamed

1
foo = function(x) return 2 * x end

递归

需要先定义局部变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
local fact -- 这一句和下一句要求分开【bug主要在这里】
fact = function(n)
if n == 0 then return 1
else return n * fact(n-1)
end
end

or

local function fact(n)
if n==0 then return 1
else return n * fact(n-1)
end
end

闭包

内部的函数体可以访问外部函数的局部变量(upvalue)

domo 重定义限制程序打开文件

1
2
3
4
5
6
7
8
9
10
do
local oldOpen = io.open
io.open = function(filename, mode)
if access_OK(filename, mode) then
return oldOpen(filename, mode)
else
return nil, "access denied"
end
end
end

局部函数

1
2
3
4
5
6
-- g can use f here
local f = function(...)
end
local g = function(...)
f()
end

递归局部函数

需要先声明

1
2
3
4
5
6
7
8
local fact
fact = function(n)
if n == 0 then
return 1
else
return n * fact(n-1)
end
end

tables

1
2
3
4
5
6
a = {}; a.x = 1;
b = {}; b.x = 1;
a ~= b

a.foo = function(x,y) return x + y end
unpack(a)-- 分离一层

block

normal

1
2
3
4
do
local i = 1
end
do return end -- 用于调试

if, while, repeat

1
2
3
4
5
6
7
8
9
10
if conditions then
elseif conditions then
end

while condition do
end

repeat
statements;
until conditions;

for

1
2
3
4
5
6
7
8
9
10
11
12
13
14
for var = beg,end,step do -- 如果为表达式一次性求职
end

for i,v in ipairs(a)
do
end

for key in pairs(v)
do
end

-- 死循环
for i = 1,math.huge do
end

iterator

  1. 使用闭包实现

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    function list_iter(t)
    local i = 0
    local n = table.getn(t)
    return function()
    i = i + 1
    if i <= n then return t[i] end
    end
    end

    t = {1,2,3}
    iter = list_iter(t)
    while true do
    local element = iter()
    if element == nil then break end
    print(element)
  2. 范性for本身实现for <var-list> in <exp-list> do end

  3. 无状态的迭代器for i,v in ipairs(a) do end

编译运行

  1. require 会搜索目录加载文件,避免同一个文件
  2. load c
    1
    2
    local path = "/xxxx/xxx.so"
    loacl f= loadlib(path, "luaopen_socket")

错误

抛出

1
2
if n then error("123") end
assert(io.read("*number"), "123")

处理

1
2
3
4
5
6
7
8
9
10
11
12
13
function foo()
error()
end

if pcall(foo) then
-- no error
else
-- error
print(debug.traceback())
-- or next way
local status, err = pcall(xxx):
print(err)
end

协同程序

Lua将所有关于协同程序的函数放置在一个名为coroutine的table里面

1
2
3
4
5
fco = coroutine.create(f) -- 创建,处于挂起状态
coroutine.resume(fco) -- 启动或者再次启动
coroutine.status(co) -- suspended/running/dead/normal

coroutine.yield() -- 函数内部挂起,yield(1,2)将返回1,2

非抢占式多线程
管道,迭代器

1
2
3
4
5
6
co = coroutine.create(func)
-- print(co)
-- print(coroutine.status(co))
-- suspended(创建成功,yeild), running, dead
-- coroutine.resume(co)
-- coroutine.yield()

  1. 第一,加载 LuaSocket 库

    require “luasocket”

  2. 第二,定义远程主机和需要下载的文件名

    host = “www.w3.org"
    file = “/TR/REC-html32.html”

  3. 第三,打开一个 TCP 连接到远程主机的 80 端口(http 服务的标准端口)

    c = assert(socket.connect(host, 80))
    上面这句返回一个连接对象,我们可以使用这个连接对象请求发送文件
    c:send(“GET “ .. file .. “ HTTP/1.0\r\n\r\n”)
    receive 函数返回他送接收到的数据加上一个表示操作状态的字符串。当主机断开连接时,我们退出循环。

  4. 第四,关闭连接

    c:close()

自定义table参数

1
2
3
4
5
6
7
8
-- t.__tostring = xxx
-- set:
local mt = { __index = t}
setmetatable(proxy, mt)

__tostring -- 打印
__index -- t[x] getter
__newindex -- t[x] setter

全局变量

1
_G[x]

局部作用域

1
2
3
4
5
6
7
8
9
10
11
12
-- 创建
a = 1 -- create a global variable
-- change current environment
setfenv(1, {_G = _G})
_G.print(a) --> nil
_G.print(_G.a) --> 1
-- 继承
a = 1
local newgt = {} -- create new environment
setmetatable(newgt, {__index = _G})
setfenv(1, newgt) -- set it
print(a) --> 1

面向对象

1
2
function Account:withdraw(v) -- a:withdraw
function withdraw(self, v) -- a.withdraw(可以互相通用)
  1. 原表中实现类的方法,算术方法包括:__add,__mul,__sub,__div,__unm,__mod,__pow,关系方法包括__eq,__lt,__le
  2. 表中找不到会访问__index(t,k)方法,更新为__newindex(t,k,v)方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    function setDefault(t,d)
    local mt = {__index=function() return d end}
    setmetatable(t,mt)
    end

    local key = {} -- trick, 唯一索引
    local mt = {__index = function(t) return t[key] end}
    fuction setDefault(t,d)
    t[key] = d
    setmetatable(t,mt)
    end
  3. 新建对象

    1
    2
    3
    4
    5
    function c:new(o)
    o = o or {}
    setmetatable(o,c)
    return o
    end

继承

1
2
3
4
5
6
7
SpecialAccount = Account:new()
s = SpecialAccount:new{limit=1000.00}
-- 多重继承
function createClass(...)
local c = {}
setmetatable(c, {__index=function(t,k) return search(k,arg) end })
end

weak表

  • 如果将一些对象放到一个数组当中,Lua将不会回收他们
  • 如果一个对象只有弱引用指向它,那么gc会自动回收该对象的内存。
  • weak 表
    一个weak引用 阻止 对象被回收,表的weak性由他的metatable__mode域来制定的,kkeyweak,vvalueweak
    1
    2
    3
    4
    5
    a, b = {}, {}
    setmetatable(a,b)
    b.__mode = \"k\"

    collectgarbage()

用途: 记忆函数,对象的属性关联

函数工厂

1
2
3
4
function newzxx(xxx):
local f = functionxx
return {f=f}
end

解析

setfenv(f, table):设置一个函数的环境
  (1)当第一个参数为一个函数时,表示设置该函数的环境
  (2)当第一个参数为一个数字时,为1代表当前函数,2代表调用自己的函数,3代表调用自己的函数的函数,以此类推

标准库

数学

简介

数学库由算术函数的标准集合组成,比如三角函数库(sin, cos, tan, asin, acos, etc.),
幂指函数(exp, log, log10),舍入函数(floor, ceil)、max、min,加上一个变量 pi。数学
库也定义了一个幂操作符(^)。
所有的三角函数都在弧度单位下工作。(Lua4.0 以前在度数下工作。)你可以使用 deg
和 rad 函数在度和弧度之间转换。

random

math.random 用来产生伪随机数,有三种调用方式:

  • 第一:不带参数,将产生 [0,1)范围内的随机数.
  • 第二:带一个参数 n,将产生 1 <= x <= n 范围内的随机数 x.
  • 第三:带两个参数 a 和 b,将产生 a <= x <= b 范围内的随机数 x.
    math.randomseed(os.time())

table

lua 假定array在最后一个非nil位置结束

1
2
3
4
5
6
table.getn -- memory search
table.setn
table.insert(a,x) -- push
table.remove(a) -- pop
table.insert(a,1,x), table.remove(a,1)
table.sort

string

1
2
3
4
5
6
string.len(s)
string.rep(s,n) -- repeat s for n times
string.lower(s) -- upper
string.sub(s,i,j) -- begin with 1. end as -1
i, j = string.find(s, "hello", [beg pos])
s, count = string.gsub(ori, mod, replace[, time])

IO

简单模式/完全模式

1
2
3
4
5
6
7
8
9
10
11
12
io.input(filename), io.output(filename)
io.read() -- a line
io.read(*all)
io.read(*number)
io.read(*line)
io.read(*num) -- char num
io.read(0) -- whether EOF
io.write("",math.sin(3),"")

f = assert(io.open("xxx.xxx", "r"))
local lines, rest = f:read(BUFISIZE,"*line")
outf:flush

os

1
2
3
os.time(year=x, month=x, day=x)
<-->
os.date("*t",1233)

debug

  1. 栈级别
  2. HOOK(call, return, line, count)

useful functions

1
2
3
string.format(fmt.."%q", unpack(arg), "1234")
table.sort(tb1, function(a,b) return (a.name>b.name) end)
io.read(*all)

(私货)SimpleFramework

既然你看到了最后,不如看下传统热更新框架~~

1
2
3
4
5
6
xxxPanel.prefab, xxx.AssetBundle=>build Windows Resource
GlobalGenerator:OnResourceInited->LuaScriptPanel->xxxPanel
GameManager.Lua->OnInitOK()->CtrlManager.Init()
Define.Lua:"xxx=xxxCtrl"
GameManager.Lua:ctrl:Awake()
LayerPanel