Lua学习笔记
Lua简介
设计目的
嵌入应用,为应用提供灵活的扩展和定制功能
Lua特性
- 轻量级
- 可扩展
- 其他特性
- 面向过程
- 自动内存管理
- 内置模式匹配
- 闭包(可以支持数据抽象,虚函数,继承和重载)
Lua应用场景
- 游戏开发
- 独立应用脚本
- Web应用脚本
- 扩展和数据库插件
- 安全系统,如入侵检测系统
Lua版Hello World
print("hello, lua")
lua hello.lua
注释
- --单行注释
- --[[ 多行注释 --]]
标识符
全局变量
不带修饰符, 默认为全局变量
Lua数据类型
- nil: 无效(可以用来“删除”变量 key = nil, type(X) == "nil" 要加双引号)
- boolean: false true (nil也为false)
- number: 双精度浮点数
- string: 字符串, 可以使用[[...]] 表示多行字符串, 运算时, 数字字符串会转化为数字, print("2"+3), 用 .. 连接字符串, 用#计算字符串长度, 如 name="hanzhichao" print(#name)
- function:由C或Lua编写的函数, 第一类值, 可以作为变量或参数, 可以为匿名函数, 如 fuction(a,b)
- userdata:表示任意存储在变量中的C数据结构,通常是struct和指针
- thread: 协程, 拥有自己独立的栈, 局部变量和指令指针
线程和协程的区别: 线程何况同时多个运行, 而协程任意时刻只能运行一个,并且处于运行状态的协程只有被挂起是才会暂停 - table: 关联数组,数组的索引可以是数字或字符串, Lua里表的索引以1开始, table不固定长度大学, 没初始的table的key都是nill
Lua变量
全局变量 a=5
局部变量 local a = 5
支持多值赋值:a, b = 1,2; a, b = b , a ; a, b = func() -- func返回两个值
应尽量使用局部变量: 1. 避免命名冲突;2.访问局部变量的速度比全局变量更快
索引: []或者.
site = {}
site['url'] = 'www.baidu.com'
print(site['url'])
print(site.url)
Lua循环
- while循环
while( a > b)
do
print(a)
end
- for循环
- 数值for循环: for i=0,100,2 do ... end 初始值,目标值, 步长(可选)
- 泛型for循环:通过一个迭代器来遍历所有值
for i,v in iparis(a)
do print(v)
end
-- 数值for循环
for i=1,f(5) do print(i) -- f(5)只会在循环开始前一次性求值,不会改变
end
Lua流程控制
false和nil为 false
true和非nil为 true, 0为true
if (a>b)
then
if(a>0)
then
print(a)
end
else
print(b)
end
Lua函数
function add(a, b)
return a+b
end
print(add(1,2)
- 函数可以作为参数传递
- 支持多返回值 return a, b
- 可变参数 function add(...)
function add(...)
local s = 0
for i,v in iparis{...} do -- {...}表示一个由可变参数构成的数组
s = s +v
end
return s
end
print(add(3,4,5,6,7))
当变长参数中可能还有一些nil时,需要使用select函数
- select("#", ...):返回可变参数的长度
- select(n, ...): 读取第n个参数
do
function foo(...)
for i=1, select("#", ...) do -- 获取参数总数
local arg = select(i, ...); -- 读取参数
print("arg", arg);
end
end
for(1,2,3,nil,5)
end
Lua运算符
算数运算符:
-
-
-
- /:加减乘除
-
-
- %:取余
- ^:乘方
- -:负号
关系运算符:
== ~= > < >= <=
逻辑运算符
and or not
其他运算符 - ..:连接字符串
-
:一元运算符,返回字符串或表长度
Lua字符串
- 单引号
- 双引号
- [[]]
转义字符
字符串操作
- string.upper("abc")
- string.lower("AbC")
- string.gsub(mainString, findString, replaceString, num): 替换
- string.find(str, substr, [init, [end]]): 返回位置
- string.reverse("abc")
- string.format("age: %d", 4)
- string.char(97)/string.byte("A")
- string.len("abc")
- string.rep("abcd",2): 拷贝
- ..: 连接字符串
- string.gmatch(str, pattern): 迭代匹配 for word in string.gmatch("Hello Lua user", "%a+") do print(word) end
匹配模式:
- .(点): 与任何字符配对
- %a: 与任何字母配对
- %c: 与任何控制符配对(例如\n)
- %d: 与任何数字配对
- %l: 与任何小写字母配对
- %p: 与任何标点(punctuation)配对
- %s: 与空白字符配对
- %u: 与任何大写字母配对
- %w: 与任何字母/数字配对
- %x: 与任何十六进制数配对
- %z: 与任何代表0的字符配对
- %x(此处x是非字母非数字字符)
Lua数组 索引从1开始
一位数组
a = {"Lua", "Totorial"}
for i=0, 2 do
print(a[i]
end
多维数组
a = {{1,2,3},{1,2,3},{1,2,3}}
for i=1,3 do
for j=1,3 do
print(a[i][j])
end
end
数组设定了指定的索引值,这样可以避免出现 nil 值,有利于节省内存空间
Lua迭代器
hash迭代(table)
for k,v in pairs(t) do
print(k, v)
end
列表迭代
array = {"a","b","c"}
for key,value in iparis(array)
do
print(key, value)
end
- 无状态迭代器(ipairs)
- 多状态迭代器
array = {"Lua", "Tutorial"}
function elementIterator (collection)
local index = 0
local count = #collection
-- 闭包函数
return function ()
index = index + 1
if index <= count
then
-- 返回迭代器的当前元素
return collection[index]
end
end
end
for element in elementIterator(array)
do
print(element)
end
Lua table(表)
-Lua table 使用关联型数组,你可以用任意类型的值来作数组的索引,但这个值不能是 nil。
-Lua table 是不固定大小的,你可以根据自己需要进行扩容。
-Lua也是通过table来解决模块(module)、包(package)和对象(Object)的。 例如string.format表示使用"format"来索引table string
t = {}
t[1]="a"
t["name"]='hzc'
t = nil -- 释放table,内存回收
Table操作方法
- table.concat(): 通过分隔符连接(类似join)
- table.insert(): 插入
- table.remove(): 删除
- table.sort(): 升序排序
Lua 模块与包
-- 定义一个名为 module 的模块
module = {}
-- 定义一个常量
module.constant = "这是一个常量"
-- 定义一个函数
function module.func1()
io.write("这是一个公有函数!\n")
end
local function func2()
print("这是一个私有函数!")
end
function module.func3()
func2()
end
return module
require("module")
print(module.constant)
module.func3()
-- 别名变量 m
local m = require("module")
加载机制
LUA_PATH
export LUA_PATH="~/lua/?.lua;;"
source ~/.profile
Lua元表(Metatable)
setmetatable(table, metatable)
getmetatable(table)
__index
__newindex
Lua协程
- coroutine.create()
- coroutine.resume()
- coroutine.yield()
- coroutine.status()
- coroutine.wrap()
- coroutine.running()
Lua文件I/O
读
file = io.open("test.lua", "r")
io.input(file)
print(io.read())
io.close(file)
写
file = io.open("test.lua", "a")
io.output(file)
io.write("hello")
io.close(file)
read模式
- *n:读取一个数字并返回
- *a:从当前位置读取整个文件
- *l(默认):读取一行
- number:读取几个字符
其他io方法
- io.tmpfile: 返回一个临时文件句柄,以更新模式打开, 程序结束后删除
- io.type(file): 检查是否是文件句柄
- io.flush():想文件中写入缓冲中所有数据
- io.lines(): 返回迭代函数, 每次读取一行
通常我们需要在同一时间处理多个文件。我们需要使用 file:function_name 来代替 io.function_name 方法
Lua 错误处理
- 语法错误
- 运行错误
pcall()
xpcall()
Lua调试
Lua面向对象
Account = {balance = 0}
function Account.withdraw (v) -- 类方法
Account.balance = Account.balance - v
end
fuction Accout:new() -- 派生类方法
...
end
-- 调用
r = Account:new()
Lua操作数据库
require "luasql.mysql"
--创建环境对象
env = luasql.mysql()
--连接数据库
conn = env:connect("数据库名","用户名","密码","IP地址",端口)
--设置数据库的编码格式
conn:execute"SET NAMES UTF8"
--执行数据库操作
cur = conn:execute("select * from role")
row = cur:fetch({},"a")
--文件对象的创建
file = io.open("role.txt","w+");
while row do
var = string.format("%d %s\n", row.id, row.name)
print(var)
file:write(var)
row = cur:fetch(row,"a")
end
file:close() --关闭文件对象
conn:close() --关闭数据库连接
env:close() --关闭数据库环境