Lua 程序设计 (Roberto,Ierusalimschy 著)
13 元表(metatable)与元方法(metamethod)
1 开始
Hello World
print("Hello World");
程序块(chunk)
一个程序块也就是一连串的语句或命令
几条连续的Lua语句之间并不需要分隔符,但如果愿意,也可以使用分号来分隔语句.
Lua通常还被作为一种数据描述语言来使用,几兆字节的程序块也是很常见的.
交互模式:
退出交互模式:UNIX(Ctrl+D),Windows(Ctrl+Z). os.exit()
运行完指定程序后进入交互模式:%lua -i prog
交互模式中使用dofile函数立即执行一个文件:
词法规范
Lua中的标识符可以是由任意字母,数字和下划线构成的字符串,但不能以数字开头
应该避免使用以一个下划线开头并跟着一个或多个大写字母的标识符,Lua将这类标识符保留用作特殊用途
Lua是有大小写之分的
行注释(--),块注释(--[[ ]])
全局变量
全局变量不需要声明
在Lua中,访问一个未初始化的变量不会引发错误,访问结果是一个特殊的值nil
解释器程序(the dtand-slone interpreter)
解释器是一个小型的程序,可以通过它来直接使用Lua
解释器程序的用法:lua [选项参数] [脚本[参数]]
选项参数"-e"可以直接在命令行中输入代码:
选项参数"-l"用于加载库文件.
在脚本代码中,可以通过全局变量arg来检索脚本的启动参数:%lua 脚本 a b c
2 类型与值
Lua是一种动态类型的语言.在语言中没有类型定义的语法.每个值都"携带"了它自身的类型信息
在Lua中,函数是作为"第一类值(first-class value)"来看待的,可以像操作其他值一样来操作一个函数值
nil(空)
nil是一种类型,它只有一个值nil,它的主要功能是用于区别其他任何值.
boolean(布尔)
boolean类型有两个可选值:false和true,这与传统的布尔值一样.然而boolean却不是一个条件值的唯一表示方式.在Lua中任何值都可以表示一个条件.Lua将值false和nil视为"假",而将除此之外的其他值视为"真".Lua在条件测试中, 将数字零和空字符串也都视为"真"
number(数字)
number类型用于表示实数.Lua没有整数类型.
string(字符串)
Lua完全采用8位编码,Lua字符串中的字符可以具有任何数值编码,包括数值0.也就是说,可以将任意二进制数据存储到一个字符串中
Lua的字符串是不可变的值(immutable values)
Lua的字符串和其他Lua对象(例如table或函数等)一样,都是自动内存管理机制所管理的对象
Lua提供了运行时的数字与字符串的自动转换
在Lua中,".."是字符串连接操作符.当直接在一个数字后面输入它的时候,必须要用一个空格来分隔它们.不然,Lua会将第一个点理解为一个小数点.
若要将一个数字转换成字符串,可以调用函数tostring,或者将数该数字与第一个空字符串相连接
在Lua5.1中,可以在字符串前放置操作符"#"来获得该字符串的长度
table(表)
在Lua中,table既不是"值"也不是"变量",而是"对象".可以将一个table想象成一种动态分配的对象,程序仅持有一个对它们的引用(或指针),Lua不会暗中产生table的副本或创建新的table.此外,在Lua中也不需要声明一个table.事实上也没有办法可以声明table.table的创建是通过"构造表达式(constructor expression)"完成的,最简单的构造表达式是{}.
table永远是"匿名的(anonymous)",一个持有table的变量与table自身之间没有固定的关联性.
当一个程序再也没有对一个table的引用时,Lua的垃圾收集器(garbage collector)最终会删除该table,并复用它的内存
function(函数)
在Lua中,函数是作为"第一类值"来看待的.这表示函数可以存储在变量中,可以通过参数传递给其他函数,还可以作为其他函数的返回值.
userdata(自定义类型)和thread(线程)
由于userdata类型可以将任意的C语言数据存储到Lua变量中.在Lua中,这种类型没有太多的预定义操作,只能进行赋值和相等性测试.
3 表达式
算术操作符
Lua支持常规的算术操作符有: + - * / ^ % -(负号)
关系操作符
Lua提供了以下关系操作符: < > <= >= == ~= 所有这些操作符的运算结果都是true或false 特别需要说明的是,nil只与其自身相等
对于table,userdata和函数,Lua是作引用比较的.也就是说,只有当它们引用同一个对象时,才认为它们相等.
只能对两个数字或两个字符串作大小性比较.而数字和字符串之外的其他类型只能进行相等性或不等性比较.
当对两个不同类型的值作比较时,要格外小心.请记住,"0"与0是不同的
逻辑操作符
逻辑操作符有and,or和not.与条件控制语句一样,所有的操作符将false和nil视为假,而将其他的任何东西视为真.
and和or都是使用"短路求值(short-cut evaluation)"
有一种常用的Lua习惯写法"x=x or v",它等价于 if not x then x = v end
字符串连接
要在Lua中连接两个字符串,可以使用操作符"..".如果其任意一个操作数是数字的话,Lua会将这个数字转换成一个字符串
请记住,Lua中的字符串是不可变的值(immutable value).连接操作符只会创建一个新字符串,而不会对其原操作数进行任何修改.
优先级
在二元操作符中,除了指数操作符"^"和连接操作符".."是"右结合"的,所有其他操作符都是"左结合(left associative)"的.
table构造式(table constructor)
最简单的构造式就是一个空构造式{},用于创建一个空table
列表风格:
记录风格:
记录风格与列表风格的混合:
通用格式:
无论是列表风格的初始化,还是记录风格的初始化,起始都是这种通用语法特例.{x=0,y=0}等价于{["x"]=0,["y"]=0},{“r","g","b"}等价于{[1]="r",[2]="g",[3]="b"}
不推荐在Lua中以0作为数组的起始索引
4 语句
赋值
赋值的基本含义(assignment)的基本含义是修改一个变量或一个table中字段的值
Lua允许"多重赋值"
在多重赋值中,Lua先对等号右边的所有元素求值,然后才执行赋值.这样可以用一句多重赋值来交换两个变量
Lua总是会将等号右边值的个数调整到与左边变量的个数相一致.
多重赋值的常见用法,交换两个变量,收集函数的多个返回值
局部变量和块(block)
Lua通过local语句来创建局部变量
与全局变量不同的是,局部变量的作用域仅限于声明它们的那个块.一个块(block)是一个控制结构的执行体,或者是一个函数的执行体再或者是一个程序块(chunk)
交互模式中每行输入内容自身就形成了一个程序块.使用do-end显示界定一个块
控制结构
用于条件执行的if,用于迭代的while,repeat和for.所有的控制结果都有一个显示的终止符:if,for和while以end作为结尾,repeat以until作为结尾
Lua不支持switch
在Lua中一个声明在循环体中的局部变量的作用域包括了条件测试
for语句有两种形式:数字型for(numeric for)和泛型for(generic for).
数字型for循环和泛型for循环有两个相同点: 1.循环变量是循环体的局部变量. 2.绝不应该对循环变量作任何赋值
数字型for的语法如下:
for var=exp1,exp2,exp3 do
<执行体>
end
var 从exp1变化到exp2,每次变化都以exp3作为步长(step)递增var,并执行一次"执行体".第三个表达式exp3是可选的,若不指定的话,Lua会将步长默认为1
泛型for循环通过一个迭代器(iterator)函数来遍历所有值
标准库提供了几种迭代器,包括用于迭代文件中每行的(io.line),迭代table元素的(pairs),迭代数组元素的(ipairs),迭代字符串中单词的(string.gmatch)
break与return
break和return语句用于跳出当前的块
5 函数
Lua为面向对象式的调用也提供了一种特殊的语法---冒号操作符.表达式o.foo(o,x)的另一种写法是o:foo(x),冒号操作符使调用o.foo时将o隐含地作为函数的第一个参数.
多重返回值(multiple results)
关于多重返回值还要介绍一个特殊函数--unpack.它接受一个数组作为参数,并从下标1开始返回该数组的所有元素:
unpack的一项重要用途体现在"泛型调用(generic call)"机制中.泛型调用机制可以动态地以任何实参来调用
变长参数(variable number of arguments)
具名实参(named arguments)
6 深入函数
closure(闭合函数)
非全局的函数(non-global function)
正确的尾调用(propertailcall)
7 迭代器与泛型for
迭代器与closure
泛型for的语义
无状态的迭代器
a = {"one","two","three"}
for i,v in ipairs(a) do
print(i,v)
end local function iter(a,i)
i = i +
local v = a[i]
if v then
return i,v
end
end function ipairs(a)
return iter,a,
end function pairs(t)
return next,t,nil
end for k,v in next,t do
<loop body>
end local function getnext(list,node)
if not node then
return list
else
return node.next
end
end function traverse(list)
return getnext,list,nil
end list = nil
for line in io.lines() do
list = {val = line,next = list}
end for node in traverse(list) do
print(node.val)
end
具有复杂状态的迭代器
真正的迭代器
8 编译,执行与错误
编译
C代码
错误(error)
错误处理与异常
错误消息与追溯(traceback)
9 协同程序(coroutine)
协同程序基础
co = coroutine.create(function() print("hi") end)
print(co) --thread:00B5C840 print(coroutine.status(co)) --suspended coroutine.resume(co) --hi print(coroutine.status(co)) --dead co = coroutine.create(function ()
for i = , do
print("co",i)
coroutine.yield()
end
end) coroutine.resume(co) --co 1
print(coroutine.status(co)) --suspended coroutine.resume(co) --co 2
coroutine.resume(co) --co 3
coroutine.resume(co) --什么都不打印 print(coroutine.resume(co)) --false cannot resume dead coroutine co = coroutine.create(function(a,b,c)
print("co",a,b,c)
end)
coroutine.resume(co,,,) --co 1 2 3 co = coroutine.create(function(a,b)
coroutine.yield(a+b,a-b)
end)
print(coroutine.resume(co,,)) --true 30 10 co = coroutine.create(function()
print("co",coroutine.yield())
end)
coroutine.resume(co)
coroutine.resume(co,,) --co 4 5 co = coroutine.create(function()
return ,
end)
print(coroutine.resume(co)) --true 6 7
管道(pipe)与过滤器(filter)
function producer()
while true do
local x = io.read() --产生新的值?
send(x) --发送给消费者
end
end function consumer()
while true do
local x = receive() --从生产者接收值
io.write(x,"\n") --消费新的值
end
end function receive()
local status,value = coroutine.resume(producer)
return value
end function send(x)
coroutine.yield(x)
end producer = coroutine.create(
function()
while true do
local x = io.read() --产生新值
send(x)
end
end) function receive(prod)
local status,value = coroutine.resume(prod)
return value
end function send(x)
coroutine.yield(x)
end function producer()
return coroutine.create(function()
while true do
local x = io.read() --产生新值
send(x)
end
end)
end function filter(prod)
return coroutine.create(function()
for line = ,math.huge do
local x = receive(prod) --获取新值
x = string.format("%5d%s",line,x)
send(x) --将新值发送给消费者
end
end)
end function consumer(prod)
while true do
local x = receive(prod) --获取新值
io.write(x,"\n") --消费新值
end
end p = producer()
f = filter(p)
consumer(f)
以协同程序实现迭代器
function permgen(a,n)
n = n or #a --默认n为a的大小
if n<= then --还需要改变吗
printResult(a)
else
for i = ,n do
--将第i个元素放到数组末尾
a[n],a[i] = a[i],a[n]
--生成其余元素的排列
permgen(a,n-)
--恢复第i个元素
a[n],a[i] = a[i],a[n]
end
end
end function printResult(a)
for i = ,#a do
io.write(a[i]," ")
end
io.write("\n")
end permgen({,,,}) function permgen(a,n)
n = n or #a
if n <= then
coroutine.yield(a)
else
<as before> function permutations(a)
local co = coroutine.create(function() permgen(a) end)
return function() --迭代器
local code,res = coroutine.resume(co)
return res
end
end for p in permutations{"a","b","c"} do
printResult(p)
end
非抢先式的(non-preemptive)多线程
10 完整的示例
暂无
11 数据结构
数组
矩阵与多维数组
链表
队列与双向队列
function ListNew()
return {first=,last=-}
end List = {}
function List.new()
return {first=,last=-}
end function List.pushfirst(list,value)
local first = list.first-
list.first = first
list[first] = value
end function List.pushlast(list,value)
local last = list.last +
list.last = last
list[last] = value
end function List.popfirst(list)
local first = list.first
if first > list.last then error("list is empty") end
local value = list[first]
list[first] = nil --为了允许垃圾收集
list.first = first +
return value
end function List.poplast(list)
local last = list.last
if list.first > last then error("list is empty") end
local value = list[last]
list[last] = nil --为了允许垃圾收集
list.last = last -
return value
end
集合与无序组(bag)
reserved = {
["while"] = true,
["end"] = true,
["function"] = true,
["local"] = true,
} for w in allwords() do
if not reserved[w] then
<对'w'作任意处理> --'w'不是保留字
end
end function Set(list)
local set = {}
for _,l in ipairs(list) do set[l] = true end
return set
end reserved = Set{"while","end","function","local"} function insert(bag,element)
bag[element] = (bag[element] or ) +
end function remove(bag,element)
local count = bag[element]
bag[element] = (count and count > ) and count - or nil
end
字符串缓冲
图
12 数据文件与持久性
数据文件
串行化(Serialization)
13 元表(metatable)与元方法(metamethod)
可以通过元表来修改一个值的行为,使其在面对一个非预定义的操作时执行一个指定的操作
Lua中的每个值多又一个元表.table和userdata可以有各自独立的元表,而其他类型的值则共享其类型所属的单一元表
Lua在创建新的table时不会创建元表:
可以使用setmetatable来设置或修改任何table的元表:
任何table都可以作为任何值的元表,而一组相关的table也可以共享一个通用的元素,此元表描述了它们共同的行为.一个table甚至可以作为它自己的元表,用于描述其特有的行为.
在Lua代码中,只能设置table的元表.若要设置其他类型的值的元表,则必须通过C代码来完成.
算术类的元方法
在元表中,每种算术操作符多有对应的字段名.__add,__mul,__sub,__div,_unm(相反数),__mod,__pow,__concat
Set = {}
local mt = {} --集合的元表 --根据参数列表中的值创建一个新的集合
function Set.new(l)
local set = {}
setmetatable(set,mt)
for _,v in ipairs(l) do
set[v] = true
end
return set
end function Set.union(a,b)
local res = Set.new{}
for k in pairs(a) do
res[k] = true
end
for k in pairs(b) do
res[k] = true
end
return res
end function Set.intersection(a,b)
local res = Set.new{}
for k in pairs(a) do
res[k] = b[k]
end
return res
end function Set.tostring(set)
local l = {} --用于存放集合中所有元素的列表
for e in pairs(set) do
l[#l + ] = e
end
return "{" .. table.concat(l,", ") .. "}"
end function Set.print(s)
print(Set.tostring(s))
end s1 = Set.new{,,,}
s2 = Set.new{,} print(getmetatable(s1))
print(getmetatable(s2)) mt.__add = Set.union s3 = s1 + s2
Set.print(s3) mt.__mul = Set.intersection
Set.print((s1 + s2)*s1)
关系类的元方法
元表还可以指定关系操作符的含义,元方法为__eq,__lt(小于),__le(小于等于).而其他3个关系操作符则没有单独的元方法,Lua会将a~=b转化为not(a==b),将a>b转化为b<a,将a>=b转化为b<=a
库定义的元方法
table访问的元方法
__index元方法
__newindex元方法
__newindex元方法与__index类似,不同之处在于前者用于table的更新,而后者用于table的查询
具有默认值的table
跟踪table的访问
只读的table
14 环境
Lua将其所有的全局变量保存在一个常规的table中,这个table称为"环境(enviroment)".Lua将环境table自身保存在一个全局变量_G中.
具有动态名字的全局变量
全局变量声明
简单地检测所有对全局table中不存在key的访问
如何声明一个新的变量,其一是使用rawset,它可以绕过元表
另外一种更简单的方法就是只允许在主程序中对全局变量进行赋值
非全局的环境
Lua5允许每个函数拥有一个自己的环境来查找全局变量
15 模块与包
require函数
如果require为指定模块找到了一个Lua文件,它就通过loadfile来加载该文件.而如果找到的是一个C程序库,就通过loadlib来加载.注意,loadfile和loadlib都只是加载了代码,并没有运行它们.
require采用的路径是一连串的模式(pattern),其中每项都是一种将模块名转换为文件名的方式
require用于搜索Lua文件的路径存放在变量package.path中.当Lua启动后,便以环境变量LUA_PATH的值来初始化这个变量.
具有良好行为的C程序库应该导出一个名为"luaopen_<模块名>"的函数.
编写模块的基本方法
在Lua中创建一个模块最简单的方法是:创建一个table,并将所有需要导出的函数放入其中,最后返回这个table.
使用环境
module函数
子模块与包
16 面向对象编程
类
继承
多重继承
--在table'plist'中查找'k'
local function search(k,plist)
for i = ,#plist do
local v = plist[i][k] --尝试第i个基类
if v then return v end
end
end function createClass(...)
local c = {} --新类
local parents = {...} --类在其父类列表中的搜索方法
setmetatable(c,{__index = function(t,k)
return search(k,parent)
end}) --将'c'作为其实例的元表
c.__index = c --为这个新类定义一个新的构造函数(construction)
function c:new(o)
o = o or {}
setmetatable(o,c)
return o
end return c --返回新类
end Named = {}
function Named:getname()
return self.name
end function Named:setname(n)
self.name = n
end NamedAccount = createClass(Account,Named) account = NamedAccount:new{name = "Paul"}
print(account:getname()) -->Paul setmetatable(c,{__index = function(t,k)
local v = search(k,parents)
t[k] = v --保存下来,以备下次访问
return v
end})
私密性
单一方法(single-method)做法
17 弱引用
备忘录函数
对象属性
回顾table的默认值
18 数学库
19 table库
插入和删除
排序
连接
20 字符串表
基础字符串函数
模式匹配(pattern-matching)函数
string.find函数
string.match函数
string.gsub函数
string.gmatch函数
模式
捕获(capture)
替换
URL编码
tab扩展
技巧
21 I/O库
sdfsdf
22 操作系统库
日期和时间
其他系统调用
23 调试库
自省机制
访问局部变量
访问非局部的变量(non-local varible)
访问其他协同程序
钩子
性能剖析(profile)
24 C API概述
第一个示例
#include <stdio.h>
#include <string.h>
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h" int main(void){
char buff[];
int error;
lua_State *L = luaL_newstate(); /* 打开Lua */
luaL_openlibs(L); /* 打开标准库 */ while(fgets(buff,sizeof(buff),stdin) != NULL){
error = luaL_loadbuffer(L,buff,strlen(buff),"line") || lua_pcall(L,,,);
if(error) {
fprintf(stderr,"%s",lua_tostring(L,-));
lua_pop(L,); /* 从栈中弹出错误消息 */
}
} lua_close(L);
return ;
}
栈
压入元素
查询元素
其他栈操作
CAPI中的错误处理
应用程序代码中的错误处理
库代码中的错误处理
25 扩展应用程序
基础
table操作
--配置文件
width =
height =
background_red = 0.30
background_green = 0.10
background_blue = background = {r=0.30,g=0.10,b=} BLUE = {r=,g=,b=}
<其他颜色定义》 background = BLUE lua_getglobal(L,"background");
if(!lua_istable(L,-))
error(L,"'background' is not a table"); red = getfiled(L,"r");
green = getfield(L,"g");
blue = getfield(L,"b"); #define MAX_COLOR 255 /* 假设table位于栈顶 */
int getfield(lua_State *L,const char *key){
int result;
lua_pushstring(L,key);
lua_gettable(L,-); /* 获取background[key] */
if(!lua_isnumber(L,-))
error(L,"invalid component in background color");
result = (int)lua_tonumber(L,-) * MAX_COLOR;
lua_pop(L,); /* 删除数字 */
return result;
}
调用Lua函数
一个通用的调用函数
#include <stdarg.h> void call_va(const char *func,const char *sig,...){
va_list vl;
int narg,nres; /*参数和结果的数量*/ va_start(vl,sig);
lua_getglobal(L,func); /*压入函数*/ for(narg = ;*sig;narg++){ /*遍历所有参数*/
/*检查栈中空间*/
luaL_checkstack(L,,"too many arguments"); switch(*sig++){
case 'd': /*double参数*/
lua_pushnumber(L,va_arg(vl,double));
break;
case 'i': /*int参数*/
lua_pushinteger(L,va_arg(vl,int));
break;
case 's': /*字符串参数*/
lua_pushstring(L,va_arg(vl,char*));
break;
case '>': /*参数结束*/
goto endargs;
default:
error(L,"invalid option(%C)",*(sig - ));
}
} nres = strlen(sig); /*期望的结果数量*/ if(lua_pcall(L,narg,nres,) != ) /*完成调用*/
error(L,"error calling '%s':%s",func,lua_tostring(L,-)); nres = -nres; /*第一个结果的栈索引 */
while(*sig){ /*遍历所有结果*/
switch(*sig++){
case 'd': /*double结果*/
if(!lua_isnumber(L,nres))
error(L,"wrong result type");
*va_arg(vl,double *) = lua_tonumber(L,nres);
break;
case 'i': /*int结果*/
if(!lua_isnumber(L,nres))
error(L,"wrong result type");
*va_arg(vl,int *) = lua_tointeger(L,nres);
break;
case 's': /*string结果*/
if(!lua_isstring(L,nres))
error(L,"wrong result type");
*va_arg(vl,const char **) = lua_tostring(L,nres);
break;
default:
error(L,"invalid option(%c)",*(sig - ));
}
nres++;
} va_end(v1);
}
26 从Lua调用C
C函数
C模块
27 编写C函数的技术
数组操作
字符串操作
lua_pushlstring(L,s+i,j-i+); static int l_split(lua_State *L){
const char *s = luaL_checkstring(L,);
const char *sep = luaL_checkstring(L,);
const char *e;
int i = ;
lua_newtable(L); /*结果*/ /*遍历所有分隔符*/
while((e=strchr(s,*sep)) != NULL){
lua_pushlstring(L,s,e-s); /*压入子串*/
lua_rawseti(L,-,i++);
s = e + ; /*跳过分隔符*/
} /*压入最后一个子串*/
lua_pushstring(L,s);
lua_rawseti(L,-,i); return ; /*返回table*/
} const char *lua_pushfstring(lua_State *L,const char *fmt,...); static int str_upper(lua_State *L){
size_t l;
size_t i;
luaL_Buffer b;
const char *s = luaL_checklstr(L,,&l);
luaL_bufferinit(L,&b);
for(i=;i<l;i++){
luaL_addchar(&b,toupper((unsinged char)(s[i])));
}
luaL_pushresult(&b);
return ;
} void luaL_buffinit(lua_State *L,luaL_Buffer *B);
void luaL_addchar(luaL_Buffer *B,char c);
void luaL_addlstring(luaL_Buffer *B,const char *s,size_t l);
void luaL_addstring(luaL_Buffer *B,const char *s);
void lua_pushresult(luaL_Buffer *B); void luaL_addvalue(luaL_Buffer *B);
在C函数中保存状态
注册表(registry)
C函数的环境
upvalue
28 用户自定义类型
暂无
29 管理资源
暂无
30 线程和状态
多个线程
Lua状态
31 内存管理
分配函数
垃圾收集器
原子操作
垃圾收集器的API
Lua 程序设计 (Roberto,Ierusalimschy 著)的更多相关文章
- lua程序设计(一)
摘要:lua程序设计第二版学习笔记 脚本语言的基础语法大都比较简单,这里只列举一些lua独有,或者需要特别注意的语法点. 书中前三章的内容是一些惯常的引言,基础数据类型,运算符等内容,相对简单,这里就 ...
- Lua程序设计之字符串精要
(摘自Lua程序设计) 基本: Lua语言的字符串是一串字节组成的序列. 在Lua语言中,字符使用8个比特位来存储. Lua语言中的字符串可以存储包括空字符在内的所有数值代码,这意味着我们可以在字符串 ...
- Lua程序设计之数值
(摘自Lua程序设计) 数值常量 从Lua5.3版本开始Lua语言为数值格式提供了两种选择:被称为integer的64位整形和被称为float的双精度浮点类型(注意,"float" ...
- 《Lua程序设计 第二版》学习笔记一
Lua简介 Lua是一种简单.可拓展.可移植及高效的脚本语言. 开始 Lua之间不需要分隔符 运行方式: Linux下: lua -i prog dofile("lib1.lua" ...
- Lua程序设计入门
在Lua中,一切都是变量,除了关键字.TTMD强大了. 1.注释 -- 表示注释一行 --[[ ]]表示注释一段代码,相当于C语言的/*....*/ 注意:[[ ... ]]表示一段字符串 2.lua ...
- lua元表和元方法 《lua程序设计》 13章 读书笔记
lua中每个值都有一个元表,talble和userdata可以有各自独立的元表,而其它类型的值则共享其类型所属的单一元表.lua在创建table时不会创建元表. t = {} print(getmet ...
- 关于Lua程序设计{读书笔记}
1.lua中的标识符可以是由任意字母.数字和下划线构成的字符串,但不能以数字开头.2.lua将通常类似"_VALUE"的标识符作为保留标识符3.lua的保留字 and break ...
- Lua程序设计(三)面向对象实现一个简单的类
1.Lua面向对象实现步骤 ①创建一个全局表(称之为元表) ②设置这个元表的__index值(值通常为元表自己,这样就能通过__index查找到对应的属性和方法)__index 赋值其实是一个func ...
- Lua程序设计(二)面向对象概念介绍
----------------------------------------------------------- Lua面向对象3 local smartMan = { name = " ...
随机推荐
- 几大principal
1.A class should have only one reason to change. 一个类只负责一件事 2.高层抽象不依赖低层实现
- Android开发 ---Activity的7种运行状态
Android开发 ---Activity的7种运行状态 创建 --> 启动 --> 运行 --> 暂停 --> 停止 --> 销毁 重启 操作图解: 1.MainA ...
- windows 访问局域网共享文件
直接在浏览器或资源管理器输入路径就OK file://10.16.73.129/FinTech/soft
- centos7安装kvm
一. 安装kvm前的准备工作 1. 清除iptables规则 service iptables save service iptables stop 2. 关闭selinux sed -i 's/SE ...
- <Spark><Running on a Cluster>
Introduction 之前学习的时候都是通过使用spark-shell或者是在local模式运行spark 这边我们首先介绍Spark分布式应用的架构,然后讨论在分布式clusters中运行Spa ...
- Nginx 自动补全url地址补全最后的斜线
参考地址: http://blog.csdn.net/dong123dddd/article/details/51660368 location /riskcontrol { root /data; ...
- js编写轮播图,广告弹框
1.轮播图 js编写轮播图,需要用到setInterval(计时器):先给一个div,里面放轮播图的图片,将轮播图的图片明明为相同样式的:如:banner1.jpg,banner2.jpg,banne ...
- 12.输入一个成绩计算其A,B,C,D,E等级
#include <stdio.h> #include <stdlib.h> #include <math.h> int main() { int score; s ...
- LeetCode--219、268、283、414、448 Array(Easy)
219. Contains Duplicate II Given an array of integers and an integer k, find out whether there are t ...
- 【Python】多线程-2
1. 进程和线程的区别: (1) 一个进程可以有多个线程,一个进程中的多个线程共享该进程的所有资源,多线程切换比多进程切换快,因为不用上下文切换,Python中并发建议用多进程 (2) 进程是资 ...