lua中的泛型for用法: for i, v inalter talbee do....end

1)">1)">1" ng-class="{current:{{currentPage==page}}}" ng-repeat="page in pages"><li class='page' ng-if="(endIndex<li class='page next' ng-if="(currentPage
相关文章阅读资料摘自&Lua程序设计(第二版)&
迭代器与泛型for
所谓&迭代器&就是一种可以遍历一种集合中所有元素的机制。在Lua中,通常将迭代器表示为函数。每调用一次函数,即返回集合中的&下一个&元素。
简单示例如下:
function valuses(t)
& & local i = 0
& & return function() i = i&#43;1;return t[i] end
t = {10,20,30}
for element in valuses(t) do
& & print(element)
泛型for的语法如下:
for &var-list& in &exp-list& do
& & &body&
其中,&var-list&是一个或多个变量名的列表,以逗号分隔;&exp-list&是一个或多个表达式的列表,以逗号分隔。
for k,v in pairs(t) do print(k,v) end
for line in io.lines() do io.write(line,&\n&) end
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:84634次
积分:1701
积分:1701
排名:第10162名
原创:68篇
转载:135篇
评论:10条
(3)(3)(4)(1)(2)(3)(3)(25)(11)(5)(3)(9)(15)(1)(1)(2)(5)(6)(18)(38)(27)(2)(12)(1)(2)(1)页面导航:
→ 正文内容 Lua极简入门指南
Lua极简入门指南(一):基础知识篇
这篇文章主要介绍了Lua极简入门指南(一):基础知识篇,本文罗列了Lua的基础知识,如注释、数据类型、table、循环控制结构等内容,需要的朋友可以参考下
本文是《Programming in Lua 3rd》读书笔记。
一个 Chunk 就是一组被执行的语句,例如一个文件或者交互模式下的一行。
标识符(identifiers)
我们应该避免使用以 _ 开头并跟上一个或者多个大写字母的字符串来作标识符,它们被保留作特殊的用途(例如:_VERSION)。
单行注释使用
多行注释使用
--[[ 和 --]]
Lua 存在的数据类型包括:
1.nil。此类型只有一个值 nil。用于表示“空”值。全局变量默认为 nil,删除一个已经赋值的全局变量只需要将其赋值为 nil(对比 JavaScript,赋值 null 并不能完全删除对象的属性,属性还存在,值为 null)
2.boolean。此类型有两个值 true 和 false。在 Lua 中,false 和 nil 都表示条件假,其他值都表示条件真(区别于 C/C++ 等语言的是,0 是真)
3.number。双精浮点数(IEEE 754 标准),Lua 没有整数类型
4.string。你可以保存任意的二进制数据到字符串中(包括 0)。字符串中的字符是不可以改变的(需要改变时,你只能创建一个新的字符串)。获取字符串的长度,可以使用 # 操作符(长度操作符)。例如:print(#”hello”)。字符串可以使用单引号,也可以使用双引号包裹,对于多行的字符串还可以使用 [[ 和 ]] 包裹。字符串中可以使用转义字符,例如 \n \r 等。使用 [[ 和 ]] 包裹的字符串中的转义字符不会被转义
5.userdata。用于保存任意的 C 数据。userdata 只能支持赋值操作和比较测试
6.function。函数是第一类值(first-class value),我们能够像使用其他变量一样的使用函数(函数能够保存在变量中,可以作为参数传递给函数)
7.thread。区别于我们常常说的系统级线程
8.table。被实现为关联数组(associative arrays),可以通过任何值来进行索引(nil 除外)。和全局变量一样,table 中未赋值的域为 nil,删除一个域只需要将其赋值为 nil(实际上,全局变量就是被放置在一个 table 中)
type 函数用于返回值的类型:
print(type("Hello World")) --& string
print(type(10.4*3))&&&&&&& --& number
print(type(print))&&&&&&&& --& function
print(type(type(X)))&&&&&& --& string
在 Lua 中,任何的变量都可以保存任何的值。
table 使用简介
使用构造表达式可以创建一个 table:
-- 创建一个空的 table
-- 创建并初始化一个 table,这里
-- days[1] == "Sunday"
-- days[2] == "Monday"
days = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" }
-- 创建并初始化一个 table,这里
-- a["x"] == 10
-- a["y"] == 20
a = { x = 10, y = 20 }
使用 [] 操作符访问 table 的域:
a["x"] = 20
print(a["y"]) --& nil
注意,a.name 的语法等价于 a["name"]。
table 可以用于表示数组,这时候索引为整数,并且从 1(而非 0)开始,例如:
a = { 'a', 'b' }
a[1] == 'a'
a[2] == 'b'
长度操作符可以获取 table 数组部分的长度:
print(#a) --& 2
print(#a) --& 2
print(#a) --& 0
算术操作符
6.%(取模)
任何算术操作符都试图将操作数转换为数值类型,例如:
print(10 + '1') --& 11
关系操作符
1.&(小于)
2.&(大于)
3.&=(小于等于)
4.&=(大于等于)
5.==(等于)
6.~=(不等于)
两个不同类型的值是不相等的,例如:
nil ~= false
table、userdata 类型是通过引用进行比较的,例如:
a = {}; a.x = 1; a.y = 0
b = {}; b.x = 1; b.y = 0
这里 a 和 c 引用一个相同的对象,因此 a == c,但是 a ~= b(即便 a、b 内容相同)。
逻辑操作符
逻辑操作符有返回值。对于 and 操作来说,如果第一个操作数为 false 时返回此操作数,否则返回第二个操作数。对于 or 操作来说,如果第一个操作数不为 false 时返回此操作数,否则返回第二个操作数。
连接操作符
字符串连接可以使用连接操作符 “..”,例如:
print("Hello " .. "World")
连接操作符试图将操作数转化为字符串,例如:
print("number: " .. 1)
多赋值(multiple assignment)支持,例如:
a, b = 1, 2
print(a) --& 1
print(b) --& 2
多赋值的一个惯用法就是交换两个变量的值:
x, y = 1, 2
x, y = y, x
print(x) --& 2
print(y) --& 1
创建局部变量使用 local:
j = 10&&&&&& -- 全局变量 j
local i = 10 -- 局部变量 i
局部变量的作用域限制于他们声明的块(block)。块(block)包括:
1.控制结构的主体部分
if true then
&&& local x = 20
&&& print(x) --& 20
print(x) --& nil
我们可以使用 do-end 关键字来构造一个块:
&&& local x = 20
&&& print(x) --& 20
print(x) --& nil
访问局部变量要快于访问全局变量。在 Lua 中有一个习惯用法:
local foo = foo
用于创建一个局部变量并初始化为同名的全局变量。这样做常常出于两个原因:
1.避免某些类型的全局变量被修改
2.提高访问速度
if then elseif else
if a & 0 then
if a & b then
&&& return a
&&& return b
if op == '+' then
&&& r = a + b
elseif op == '-' then
&&& r = a - b
elseif op == '*' then
&&& r = a * b
elseif op == '/' then
&&& r = a / b
&&& error('invalid operation')
Lua 中没有 switch 语句。
local i = 1
while a[i] do
&&& print(a[i])
&&& i = i + 1
&&& line = io.read()
until line ~= ''
print(line)
区别于 while,repeat 会先执行循环体,然后判断测试条件。
数值型 for(numeric for)
for 有两种:
数值型 for(numeric for)
1.泛型 for(generic for)
2.数值型 for 的语法如下:
for var = exp1, exp2, exp3 do
&&& &something&
这里 exp1 作为 var 的初始值,exp2 为 var 的最大值,exp3 为 var 每次递增的值,exp3 是可选的,默认为 1。范例:
-- 输出 1 2 3
for i = 1, 3 do
&&& print(i)
有一些需要注意的地方:
1.for 中的 exp1、exp2、exp3 只会被计算一次值,例如:
for i = 1, f(x) do print(i) end
这里的 f(x) 只会被调用一次
2.控制变量 var 只是一个局部变量
3.不要尝试去修改控制变量 var 的值(结果是未知的)
泛型 for 通过一个迭代器函数来实现遍历,例如:
for k, v in pairs(t) do
&&& print(k, v)
这里的 pairs 就是一个迭代器函数,此 for 循环遍历 table t,每次获取到的 key 保存在变量 k 中,获取到的 value 保存在变量 v 中。除了 pairs 还有其他的迭代器可以用:
1.io.lines 可用于迭代文件中的行
2.ipairs 可用于迭代 table 的数组部分
我们还可以自己编写迭代器。
break、return、goto
break 语句用于跳出一个循环(for、repeat、while)。
return 语句用于为函数返回结果。在 Lua 中,return 语句必须是一个块的最后一条语句,看一个例子:
function foo()
&&& -- 语法错误
&&& return
&&& local i = 1
有时候,我们出于某些原因(例如为了 debug),我们需要在一个函数中插入一个 return 语句,这时候可以这么做:
function foo()
&&& -- ...
&&& do return end
&&& -- ...
goto 语句用于在函数中跳转。goto 语句可以让执行跳转到特定的标签(label)处,例如:
print('come on')
print('quit')
这里输出 quit。正如我们看到的,标签的写法为 ::name::。goto 跳转也是存在限制的:
1.不允许跳转到一个块中去
2.不允许跳转到函数之外去
3.不允许跳入局部变量的作用域中
对于第三点,看一个例子:
print('quit')
这里,会出现语法错误(jumps into the scope of local 'a')。但是,有一个细节需要注意,我们先修改上面的例子:
执行成功,没有语法错误。这是因为局部变量的作用域结束于变量定义的块的最后一个非 void 语句,而标签被认为是一个 void 语句,对于上面的例子来说,a 的作用域在 ::quit:: 之前就结束了,因此 goto quit 并没有跳入局部变量 a 的作用域中。
利用 goto 可以比较方便的编写状态机,例如(s1、s2 为状态):
&&& local c = io.read(1)
&&& if c == '0' then goto s2
&&& elseif c == nil then print'ok'; return
&&& else goto s1
&&& local c = io.read(1)
&&& if c == '0' then goto s1
&&& elseif c == nil then print'not ok'; return
&&& else goto s2
您可能感兴趣的文章:
上一篇:下一篇:
最 近 更 新
热 点 排 行
123456789103991人阅读
范型for循环:
-- print all values of array 'a'
a={1,2,3,4,5,6,7};
for i,v in ipairs(a) do print(v) end
范型for遍历迭代子函数返回的每一个&#20540;。
再看一个遍历表key的例子:
-- print all keys of table 't'
map = {[&gaoke&]=1,[&gaoxin&]=2,[&maqiang&]=3}
for k in pairs(map) do
&print (k);
&print (map[k]);
end范型for和数&#20540;for有两点相同:
1. 控制变量是局部变量
2. 不要修改控制变量的&#20540;
-----------------------------------------------------------------
lua的dowhile循环和C语言的又有区别:
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:715394次
积分:8118
积分:8118
排名:第790名
原创:90篇
转载:109篇
评论:28条
(10)(6)(2)(1)(2)(1)(1)(3)(1)(9)(2)(7)(1)(4)(2)(2)(1)(1)(1)(1)(17)(1)(19)(14)(13)(18)(2)(5)(4)(5)(22)(11)(4)(2)(4)1、lua中的标识符可以是由任意字母、数字和下划线构成的字符串,但不能以数字开头。2、lua将通常类似"_VALUE"的标识符作为保留标识符3、lua的保留字 and break do else elseif end false for function if in loacl nil not or repear return then true until while
有大小写之分
4、行注释--
块注释--[[
]]==============================================================全局变量lua中访问一个未初始化的变量不会引发错误,结果是一个nil。如果要删除某个全局变量的话置其为nil==============================================================
**************************************************************2、类型与值lua是动态类型的语言lua中有8中数据类型nil、boolean、number、string、userdata、function、thread、tableeg:print(type(5)) --&number
false和nil规定为假,其余为真但有一点不同,在条件测试中,将数字零还有有空字符串也都视为真。
lua中的字符串是不可变值eg:a="hello world"b=string.gsub(a, "world", "lua");lua字符串和其他lua对象(table或函数等)一样都是自动内存管理机制所管理的对象。
]]来界定一个字母字符串eg:page=[[i like luai like c++i like java]]如果第一个字符是换行字符,那么lua会忽略它。
数字与字符串自动转换,lua会尝试将该字符串转换成数字 但是最好不要依赖----------------
..是字符串连接操作符
如果需要显示地将一个字符串转换成数字,可用tonumber,当不能正确表示时返回nil
若要转换成字符串,可以调用tostring或者与空字符串连接。
在lua5.1中,可以在字符串前放置操作符&#&来获取改字符串的长度
5、tabletable类型实现了"关联数组"。可以以一种简单、统一和高效的方式来表示普通数组、符号表、集合、记录、队列、和其他数据结构。lua也是通过table来表示模块、包和对象的。eg:io.read表示"io模块中的read函数"对于lua,这表示"使用字符串read"作为key来索引table.io把table理解为对象eg:a = {}k = "x"a[k] = 10;a[20] = "great";
当程序再也没有一个table的引用时,lua的垃圾收集器最终会删除该table并复用其内存
a["name"] --&a.namea.x --&表示a["x"],表示以字符串"x"来索引tablea[x] --&表示以变量x的值来索引table
//若要表示一个传统的数组或线性表a={}for i=1,10 doa[i]=io.read()end
lua通常以1作为索引的起始值。
打印a中所有元素for i=1,#a doprint(a[i])end
5.1中,长度操作法"#"用于返回一个数组或线性表的最后一个索引值table.maxn() 返回一个table的最大正索引数,这是lua 5.1的新函数5.0中可以用talbe.getn(a)获取
6、function在lua中,函数是作为"第一类值"来看待的。这表示函数可以存储在变量中,可以通过参数传递给其他函数还可以作为其他函数的返回值。
7、uerdata(自定义类型)和thread(线程)userdata用于表示一种由应用程序或C语言库所创建的新类型。*************************************************************3、表达式1、算术操作符+、-、*、/、^、%、-(负号)
2、关系操作符&、 &、 &=、 &=、 ==、 ~=
对于table、userdata以及函数,lua是作引用比较的。
3、逻辑操作符and or not
对于and,如果第一个操作数为假,就返回第一个操作数否则返回第二个操作数。[即哪个假返回哪个除非都是真则返回第二个]
对于or,如果第一个操作数为真,就返回第一个操作数,否则返回第二个操作数[即哪个真返回哪个除非都是假则返回第二个]
and的优先级高于or
4字符串的连接 ..
5、优先级^not # -* / %+ -..& & &= &= -= ==andor
6、table构造器其他方式a = {"1","2","3"}a = {x=10, y=20} --& a = {} a.x=10 a.y=20;
lua很少会用到链表,列表数据一般是通过数组实现。
op={["+"]="add", ["-"]="sub"}i=20;s="-"op2={[i+0]=s,s[i+1]=s..s}[]这种格式允许在方括号之间,显shi地用一个表达式来初始化索引值
事实上 {x=0,y=0} --& {["x"]=0,["y"]=0}{"r","g","b"} --& {[1]="r",[2]="g",[3]="b"}*********************************************************4、语句
1、lua允许多重赋值,即对对多个值赋予多个变量即 a,b = 10, 2*x2、j=10 --全局变量loacl i=1 --局部变量
在交互模式中,每行输入内容自身就形成了一个程序块。如果一条声明语句没有初始化赋值,那么它声明的所有bianliang都会被初始化为nil
3、1、if then else \ elseif2、while value do ... end3、repeat .... until ... 为真的时候结束4、在lua中,一个声明在循环体中的局部变量的作用域包括了条件测试
这是5.1的新功能。
5、for语句有两种形式 数字型for和泛型for--数字型for for var=exp1,exp2,exp3 do .... end exp3默认为1可以不指定 如果不想给循环设置上限,那么可以使用常量math.huge--泛型for 通过一个迭代器函数来遍历所有值 for i, v in ipairs(a) do print(v) end ipairs是一个用于遍历数组的迭代器函数 io.lines 用于迭代文件中每行 pairs 用于迭代table元素 string.gmatch 用于迭代字符串中单词
*******************第5章 函数***********************1、所有kua标准程序库中的函数都是用C语言编写的。lua具有一项非常与众不同的特征,允许函数返回多个结果。eg:s,e=string.find("hello lua world", "lua")
--& 7,9 返回起始与结尾索引
function foo0() end 无返回值function foo1() return "a" endfunction foo2() return "a","b" end
当foo2出现在一个表达式中时,luia会将其返回值数量调整为1eg:print(foo2() .. "lua") -- alua
类似return f() 这样的语句将返回f的所有返回值print((foo2())) --将迫使它返回一个值
unpack函数,它接收一个数组作为参数,并从下表1开始返回该数组的所有元素,重要用途用于"泛型调用"机制中。
2、变长参数
function add(...)local s=0for i, v in ipairs{...} do
--注意括号为{}s=s+vendreturn send
function foo(a,b,c) &--& function foo(...)第二种形式更简洁
function args(...)local a,b,c=...print(a,b,c);end
lua提供了专门用于格式化文本string.format以及输出文本io.write的函数
用函数select()访问可变形参
select("#",...) 返回形参总数select("n",...) 返回第n个形参
3、具名实参
*******************第6章 深入函数****************************
第一类值 表示在lua中函数与其他传统类型的值具有相同的权利。可以存储到变量中或table中,可以作为实参传递给其他函数还可以作为其他函数的返回值。
词法域 指一个函数可以嵌套在另一个函数中,内部函数可以访问外部函数中的变量。
a={p=print}a.p("hello world");
一个函数定义实际上是一条赋值语句
function foo(x) return 2*x end -& foo function(x) return 2*x end
table.sort 排序 ??
1、closure是指一个函数及一系列这个函数会访问到"非局部变量"。function sortByGrade(name,grades)table.sort(name,function(n1,n2) return grades[n1] & grades[n2] end) end
比如grades
function newCounter()local i = 0;print("enter")return function() i = i + 1 return i end end非局部变量--i回调函数
创建一个安全的运行环境-所谓的沙盒sandbox--closure
2、非全局的函数
Lib={}Lib.foo=fucntion(x,y) return x+y endLib.goo=fucntion(x,y) return x-y end
Lib={ foo=fucntion(x,y) return x+y end, goo=fucntion(x,y) return x-y end}
Lib={}fucntion Lib.foo(x,y) return x+y endfucntion Lib.goo(x,y) return x-y end
--------local f = fucntion(...) body endlocal g = function(...) body .. f() .. end -- f是可见的-------local function f(...) body end
当lua展开局部函数定义的&语法糖&时,并不是使用基本函数定义语法。而是对于局部函数定义local function foo(...) body endlua将其展开为local foofoo = function foo(...) body end
向前声明local f,g function g() ... endfunction f() g() end
3、尾调用当一个函数调用时另外一个函数的最后一个动作时,该调用才算是一条尾调用。eg:fucntion f(x) return g(x) end g(x)执行完能够返回到调用f的点上,即抛弃f
一条&尾调用&就好比是一条goto语句。在lua中的应用就是编写状态机
尾调用消除可以防止栈溢出。
******************第7章 迭代器与泛型for**************************
每一个迭代器都需要在每次成功调用之间保持一些状态,这样才能知道它所在的位置以及如何进到下一个位置。closure对于这类任务提供了极佳的支持。
2、泛型for泛型for在循环过程内部保存了迭代器函数实际上它保存着3个值一个迭代器函数、一个恒定状态和一个控制变量for &var-list& in &exp-list& do &body&end
&exp-list&通常只有一个元素,即一个对迭代器工厂的调用
for所做的第一件事情就是对in后面的表达式求值。这些表达式应该返回3个值供for保存:迭代器函数、恒定状态和控制变量的初值
类似多重赋值...之后 for会以恒定状态和控制变量来调用迭代器函数
3、无状态的迭代器就是自身不保存任何状态的迭代器。因此可以在多个循环中使用同一个无状态的迭代器,避免创建新的closure开销。
典型例子就是 ipairs
8、具有复杂形态的迭代器通常,迭代器需要保存许多状态,但是泛型for只提供了一个恒定状态和一个控制变量用于状态的保存。一个解决方法是closure。或者使用table保存多个字段
----------尽可能编写无状态迭代器----------基于closure实现会比table更为高效。因为开销廉价而且访问&非局部变量&比table字段更快。
******************第8章 编译执行与错误**************************
dofile用于运行lua代码块loadfile不会运行代码,只是编译代码。然后将编译结果作为一个函数返回
如果需要多次运行一个文件,那么只需调用一次loadfile后多次调用它的返回结果就好了。对于dofile来说,开销更小。
loadstring有点类似loadfile,不同之处在于它是从一个字符串中读取代码,而不是文件读取。
f=loadstring("i=i+1") --& f = function() i = i+1 end
但是第二种代码快得多,
只在编译对应程序块时被编译一次而调用loadstring时都被重新编译
loadstring在编译时不涉及词法域,这是因为总是在全局环境中编译它的字符串loadstring最典型的用处是执行外部代码,也就是那些位于程序之外的代码。loadstring的期望输入是一个程序块,也就是一系列语句如果需要对一个表达式求值,则必须在其之前添加return才能构成语句。
string.rep("*",f())根据指定次数复制一个字符串
loadstring("a=1") --& function(...) a=1 end
----error-----对于lua,通常嵌入在应用程序中,因此发生错误时不能简单地崩溃或退出。相反,应该结束当前程序块并返回应用程序。
print "enter a number"n = io.read("*number")if not n then error("invalid input") end
--& print "enter a number" n = assert(io.read("*number"), "invalid input")--因为类似if not&condition& then error end 通用所以被build-in在assert中
lua提供的所有关于动态链接库的功能都聚集在一个函数中 package.loadlib(path, "function name")将一个C函数作为一个Lua函数返回,如果错误返回nil
loadlib是一个非常底层的函数通常使用requir来加载C程序库,它会搜索指定的库,然后用loadlib来加载库,并返回初始化函数
----------handle and catch-------------大多应用程序会处理lua的异常。如果需要lua自己处理异常,需要使用pcall函数来包装
function trackback()local status, err = pcall(function() a = "a" + 1 return a end)print(status, err)end
function trackback()local status, err = pcall(function() error("what the fuck") end)print(status, err)end
返回bool值以及包含错误行数的错误信息
******************第9章 协同程序 coroutine**************************
协同程序与线程差不多一条执行序列,拥有自己独立的栈,局部变量和指令指针同时又与其他协同程序共享全局变量和其他大部分东西
lua将所有有关协同程序的函数放置在一个名为 "coroutine"的 table中create用于创建新的协同程序,参数为函数,返回值为thread类型
function testCreate() co = coroutine.create(function() print "hi" end) print(co)end
4种不同状态挂起suspended运行running死亡dead正常normal
当create后,不会自动运行,处于suspended状态
resume是在保护模式中进行的,如果一个协同程序在执行中发生任何错误lua是不会显示错误消息的,而是返回给resume调用。
可以通过一对resume-yield来交换数据第一次调用resume时并没有对应的yield在等待它因此所有传递个resume的额外参数都将视为协同程序主函数的参数。
yield返回的额外值就是对应resume传入的参数。
function pass_data() co = coroutine.create(
function(a,b,c)
print("co", a, b, c);
end ) return coend
function pass_to_yield() co = coroutine.create(
function(a, b)
coroutine.yield(a+b, a-b)
end ) return coend
协同程序的经典实例 生产者与消费者
过滤器filter 过滤器是一种位于生产者和消费者之间的处理功能可用于对数据的一些变换。它既是生产者又是消费者。
类似Unix的pipe协同程序也是一种多线程。但协同程序是非抢占式的--socket.lua--以后再仔细看。
******************第10章 完整实例 以后查看*************************
********************************************************************
********************************************************************
********************** 第11章 数据结构 ****************************
在lua中,table是所有数据结构的基础
使用整数来索引table即可在lua中实现数组。a = {} #a用来获取数组长度在lua中的约定是一般以1作为数组的起始索引。
在lua中,有两种方式用来表示矩阵
一种是 table的每一个元素是另一个table
function multi_array() N = 3; M = 3; mt = {} for i = 1, N do
mt[i] = {}
for j = 1, M do
mt[i][j] = 0
print(mt[2][2]);end
比起C等创建多维数组例如三角矩阵可以只占用原来的一半空间
第二种方式是将两个索引合并为一个索引 -- 稀疏矩阵
--链表function link_array() list = nil while true do
x = io.read()
if x == "r" then
list = { next = list, value = x} end
print("----------------") while list do
print(list.value)
list = list.next endend
--队列与双向队列
在lua中实现队列的一种简单方法是使用table库的函数insert和remove但是对于比较大的结构,移动开销很大,一种高效方法是使用两个索引,用于首尾元素
==作为以后参考例子
--集合与无序组 --有些不懂 以后再看
--字符串缓冲
io.read("*all") 可一次性读取文件使用table作为缓冲区,使用table.concat将给定列表的所有字符串连接起来,并返回结果
table.concat与 io.read("*all")的算法类似 -- 以后再看吧
--图 以后再看吧...
********************** 第12章 数据文件以及持久性 ****************************
Entry({ "JAY", "Fantasy", "21", "1991"})
local path = "../data/persistent.txt"local count = 0;function Entry()count = count + 1 enddofile(path)print(count);
采用了事件驱动的做法,Entry函数作为一个回调函数
--串行化 [有环无环 ... ]将数据转换为一个字节流或字符流然后将其存储到一个文件或者通过网络连接发送出去
********************** 第13章 元表与元方法 ****************************
lua中每个值都有一套预定义的操作集合,如数字相加等。但无法将两个table相加,此时可通过元表修改一个值的行为,使其在面对一个非预定义的操作时执行一个指定操作。
访问机制一般的元方法都只针对Lua的核心,也就是一个虚拟机。它会检测一个操作中的值是否有元表,这些元表是否定义了关于次操作的元方法。例如两个table相加,先检查两者之一是否有元表,之后检查是否有一个叫&__add&的字段,若找到,则调用对应的值。&__add&等即时字段,其对应的值(往往是一个函数或是table)就是&元方法&。
setmetatable(只能用于table)和getmetatable(用于任何对象)
setmetatable (table, metatable),对指定table设置metatable
【如果元表(metatable)中存在__metatable键值,setmetatable会失败】
tmeta = getmetatable (tab),返回对象的元表(metatable)
【如果元表(metatable)中存在__metatable键值,当返回__metatable的值】
********************** 第14章 环境 ****************************
lua的所有全局变量保存在一个常规的table中,这个table称为环境..environment将table自身保存在一个_G中
---具有动态名字的全局变量what is meta-programming? --例子有些难懂 以后看
--全局变量声明lua中的全局变量不需要声明就可以使用 --例子有点奇怪
--非全局的环境lua允许每个函数拥有一个自己的环境来查找全局变量
可通过setfenv(1, {})改变一个函数的环境,一旦设置会失去之前所有全局变量第一个参数是一个函数和一个新的环境table
另一种组装新环境的方法是使用继承。
每个函数以及某些closure都有一个继承的环境。
a= 5function factory() return function() return a endend
f1 = factory();f2 = factory();
print(f1());print(f2());
setfenv(f1, {a = 10})print(f1());print(f2());
print---------------------------------------------------------55105--------------------------------------------------------------
每一个新创建的函数都继承了创建它的函数环境
********************** 第15章 模块与包 ****************************
模块系统的一个主要目标是允许以不同的形式来共享代码
一个包就是一系列模块
require 用于使用模块module 用于创建模块
如果require为指定模块找到了一个lua文件则通过loadfile来加载该文件如果找到的是一个C程序库,则通过loadlib来加载。
loadfile和loadlib都只是加载了代码,并没有运行它们
假设路径为 ?;?.c:\windows\?;/user/local/lua/?/?.luarequire会用模块名来替换每个?根据替换结果检查是否存在这样的文件。如果不存在就下一项。
LUA_PATHLUA_CPATH
一般通过模块来使用他们有时一个模块有不同版本
---编写模块的基本方法最简单的:创建一个table并将所有需要到处的函数放入其中最后返回这个table
一个模块无返回值的话require就会返回package.loaded[modname]的当前值
---使用环境让模块的主程序块有一个独占的环境
--module函数module()
--子模块与包
看的好晕-------------------------------
********************** 第16章 面向对象编程 ****************************
lua中的table就是一种对象。
table与对象一样可以拥有状态。table也与对象一样拥有一个独立于其值的标识selftable与对象一样具有独立于创建者和创建地的生命周期
Account = {balance = 0}function Account.withdraw(v) print(Account.balance) Account.balance = Account.balance - v print(Account.balance)end
a = AccountAccount = nilAccount.withdraw(100.00); --error------------------------------------------
Account = {balance = 0}
function Account.withdraw(self, v) print(self.balance) self.balance = self.balance - v print(self.balance)end
a1 = AccountAccount = nil
a1.withdraw(a1, 100.00)
lua使用冒号,隐藏self参数。
Account = {balance = 0}
function Account:withdraw(v) print(self.balance) self.balance = self.balance - v print(self.balance)end
a1 = AccountAccount = nil
a1:withdraw(100.00)
lua没有类的概念对象是没有类型的。而是每个对象都有一个原型。
如果有对象a和b,要让b作为a的原型a = {};b = { value = 100};setmetatable( a, {__index = b})
-----------继承
Account = {balance = 0}
function Account:new(o) o = o or {} self.__index = self setmetatable(o, self) return oend
function Account:deposit(v) self.balance = self.balance + vend
function Account:withdraw(v) if v & self.balance then error "insufficient funds" end self.balance = self.balance - vend
SpecialAccount = Account:new()
s = SpecialAccount:new({limit = 1000.00})
function SpecialAccount:getLimit() return self.limit or 0;end
function s:getLimit() return 200end
--重写function SpecialAccount:withdraw(v) if v & self.balance then error "超过余额~" end if v & self:getLimit() then error "not get more than" end self.balance = self.balance - vend
s:deposit(1000.00)s:withdraw(100.00)print(s.balance)
--多重继承【以后再看】
Smalltalk规定所有变量都是私有的,但所有的方法都是公有的。第一个面向对象语言Simula则不提供任何形式的私密性保护。
Lua也没有私密性保护。定位于 开发中小型的程序。
通过两个table来表示一个对象一个table用来保存对象的状态另外一个用于对象的操作
function newAccount(initialBalance) --用于保存对象的内部状态 local self = {balance = initialBalance}
local withdraw = function(v) self.balance = self.balance - v end local getBalance = function() return self.balance end --返回了一个供外部使用的函数 return {
withdraw = withdraw,
getBalance = getBalance
acc1 = newAccount(100.00)acc1.withdraw(40.00)print(acc1.getBalance());
--单一方法做法 【以后看看】
********************** 第17章 弱引用table ****************************
Lua采用了自动内存管理垃圾回收器只能回收它认为是垃圾的东西不能回收用户认为是垃圾的东西
当一个对象处于数组中时,它就无法被回收。
weak table 用来告诉lua一个引用不应该阻碍一个对象的回收
不管是哪一种类型的弱引用table只要有一个key或value被回收了那么它们所在的整个条目都会从table中删除。
一项通用的编程技术是&用空间换时间&例如记录下函数的计算结果,然后当调用同一个函数时便可复用之前的运行结果
-- memoize methodlocal results = {}function mem_loadstring(s) local res = results[s] if res == nil then
res = assert(loadstring(s))
results[s] = results end return resend
虽然有些命令会重复出现,但还有许多命令只发生一次。会消耗内存..因此得用弱引用table
local results = {}setmetatable(results, {__mode = "v"})function createRGB(r, g, b) local key = r.."-"..g.."-"..b local color = results[key] collectgarbage() if color == nil then
color = {red = r, green = g, blue = b}
results[key] = color end
return colorend
对象属性 与 回顾table的默认值 以后看看--
**************************************************
第18章 到 第20章 先跳过
**************************************************
**********************
第23章 调试库 ****************************
调试库并没有提供一个Lua的调试器而是提供了一个便写调试器所必须具有的原语。其性能不高,而且用户也不希望使用。
debug=nil --删除库
调试库由两类函数构成自省函数:允许检查一个正在运行中程序的各个方面钩子:允许跟踪一个程序的执行
t = debug.getinfo(foo) 得到一个table 里面包含了字段
当用一个数字&n&调用debug.getinfo(n)就可以得到相应栈层上函数的数据
1--可以得到调用debug.getinfo的那个函数的数据如果n大于栈中函数总数时,返回nil。
可以让getinfo获取指定信息
---访问局部变量[不知道怎么用]
debug.getlocal来检查任意活动函数的局部变量参数:函数栈层,变量的索引。返回:变量的名字,当前值。
Lua按局部变量在一个函数中的出现顺序为他们编号但编号只限于在函数的当前作用域中活跃的变量。
debug.setlocal改变局部变量的值参数:函数栈层,变量的索引,新值返回:变量名
局部变量只有执行过它们的初始化代码后才可见。
---访问非局部变量[不知道怎么用]
getupvalue可以访问一个lua函数所使用的非局部变量。
[被一个函数所引用的&非局部的变量&会一直存在着,即使这个引用它的函数已经执行完毕了--closure]
参数:函数closure,变量索引返回
setupvalue
-----------------------------------------访问其他协同程序 --- 看不懂 唉 以后看
----钩子钩子机制可注册一个钩子函数,这个函数会在程序运行中某个特定事件发生时被调用。
debug.sethook钩子函数字符串 描述了需要监控的事件可选的数字 用于说明多久获得一次count事件
--性能剖析 profile
---------------------第4部分--------------------------------
------------------------第24章 C API概述-----------------------------
lua是一种嵌入式语言即lua不是一个单独运行的程序而是一个可以连接到其他程序的库。通过链接就可以将lua的功能合并入这些程序。
事实上,Lua解释器是一个简单的应用程序。Lua的解释器程序(lua.c)就是&应用程序代码&的一个实例
lua解释器依靠lua库来实现主要功能。这个程序会处理与用户的交互,会将用户的文件或字符串输入lua库,由lua库来完成主要工作。
C API是一组能使C代码与lua交互的函数。其中包括读写lua全局变量调用lua函数运行一段lua代码以及注册C函数以供lua代码调用 等
lua与C语言通信的主要方法是一个虚拟栈。几乎所有API的调用都会操作这个栈上的值。
&lua.h&定义了Lua提供的基础函数 -- 保持原子性和正交性,所有定义以lua_前缀&lauxlib.h&定义了一个辅助库(使用lua.h中API编写的一个较高的抽象层)--侧重于解决具体的任务。所有定义都是以luaL_开头Lua的所有标准库编写都用到了辅助库。
lua库中没有定义任何全局变量所有状态保存在动态结构lua_State中
所有C API都要求传入一个指向该结构的指针
luaL_newstate函数用于创建一个新环境(或状态)--不包含预定义函数。&lualib.h&定义了打开这些库的函数--辅助库函数luaL_openlibs则可以打开所有的标准库
luaL_loadbuffer用来编译用户输入的每行内容。没有错误则返回0并压入栈
lua_pcall将程序块从栈中弹出并在保护模式中运行,返回0表示没有错误
lua_tostring可获取消息
lua_pop可弹出删除
lua的核心是不会直接将任何内容写到任何输出流中当发生错误时,它只会返回错误代码或错误消息来通知调用者。
lua与C之间交换数据时有两个问题:1、动态类型与静态类型区别2、自动内存管理与手动内存管理区别
-----------------------------------------------------------------联合数据类型(Union)是一种特殊的数据类型。它可以实现:以一种数据类型存储数据,以另一种数据类型来读取数据。-----------------------------------------------------------------
Lua的设计目标不仅仅是为了便于C/C++访问,还可以被比如Java、Fortran、C#等语言访问。Lua使用了垃圾回收机制,如果将一个lua table保存在一个C变量上lua引擎无法搜索出,有可能会被回收。
对于每种lua中的C类型,API都有一个对应的压入函数。
lua_checkstack 用于检查栈是否有足够的空间
Lua API使用索引(从1[栈底]开始或从-1[栈顶]开始)lua_is* -- 不会检查值是否为数字类型,而是检查值能否转换为数字类型lua_type -- 返回栈中元素的类型lua_to* -- 用于从栈中获取一个值
当lua调用一个C函数返回时,lua就会清空它的栈。这形成了一条规则,不要在C函数之外使用在C函数内获得的指向lua字符串的指针。
lua_gettop -- 返回栈中元素个数,也可以说栈顶元素的索引! 【切记】
---------------------------------------------------------lua_open是5.0时代的产物,5.1是luaL_newstate的宏,5.2里面已经没有了..
luaL_newstate用C运行库的内存分配函数。lua_newstate可自定义内存分配函数。--------------------------------------------------------------------
C没有提供异常处理机制lua使用C语言中setjmp机制,类似于异常处理的机制。
在lua中有许多地方可能会发生内存分配错误。用抛出错误 longjmup , 而不是返回错误..longjmp
当编写库代码(被lua调用的C函数)当编写应用程序代码(调用lua的C代码)
大多数应用程序包括lua解释器程序都采用让代码在保护模式下运行它们调用lua_pcall来运行lua代码。
如果要保护那些与lua交互的C代码 可以使用lua_cpcall
当一个C函数检测到一个错误时就应该调用lua_errorlua_error函数会清理lua中所有需要清理的东西然后跳转会发起执行的那个lua_pcall并附上一条错误消息
------------------------第25章 扩展应用程序-----------------------------
Lua的一项重要用途--作为一种配置语言(configuration language)
------------------------第26章 从Lua调用C-----------------------------扩展Lua的一项基本含义就是,应用程序将新的C函数注册到Lua中。
Lua能调用部分C函数,并非任意。有些扩展支持Lua调用任意C函数,但是不可移植且不安全。
C和Lua之间遵循着一个简单的协议才能够进行通信
每一个函数都有自己的局部私有栈。栈不是一个全局性的结构。
-------------------------
所有注册到Lua中的函数都具有相同的原型
typedef int (*lua_CFunction) (lua_State *L);在lua中是以函数指针的形式调用函数, 并且所有的函数指针都必须满足这种类型。
只有一个Lua状态的参数和一个表示压入栈中的返回值数量。返回后lua会自动删除栈中结果之下的内容
C模块----------------------------------------------
Lua模块是一个程序块chunk,其中定义了一些Lua函数这些函数通常存储为table的条目。
一个为Lua编写的C模块可以模仿这种行为。
除了C函数的定义外还必须定义一个特殊函数(相当于lua模块的主程序块)它应该注册模块中所有的C函数
Lua通过这个注册过程记录下C函数使用这些函数地址直接调用它
通常C模块中有一个公共外部函数用于创建C模块而其他所有函数都是私有的声明为private
如何将C代码编译成动态链接库lua便可以使用require 去加载。
LuaL_register(L,"","")
------------------------第27章 编写C函数的技术 [先跳过]-----------------------------这一章介绍了如何通过C语言编写新函数来扩展Lua
------------------------第28章 用户自定义类型 [先跳过]-----------------------------
如何用C编写新类型来扩展Lua
------------------------第29章 管理资源 [先跳过]-----------------------------
------------------------第30章 线程和状态 -----------------------------
Lua不支持共享内存的抢先式多线程。
1、ANSI C没有提供这样的功能。2、不是一个好的选择
....抢先式的线程和共享的内存 会有些无法预料的问题..比如..
Lua的协同程序是协作式的 collaborative可避免不可预知的线程切换所带来的问题另外Lua的多个状态之间不共享内存。
--------------------------------多个线程----------------------------------------------------------------在Lua中,一个线程本质上就是一个协同程序。从C API的角度上看 将线程想象成一个栈可能更形象些。
当调用Lua C API的大多数函数时这些函数都作用与某一个特定的栈。
只要创建了一个Lua状态Lua就会自动在这个状态中创建了一个新线程。称之为主线程。主线程永远不会被回收当使用lua_close关闭状态时它会随状态一起释放。
lua_newthread可以在一个状态中创建其他的线程。
不要使用未被正确系缚[指一个Lua对象既不在栈中,又不为其他任何Lua对象所引用的情况]的线程。有可能已经被垃圾回收。
切记必须确保改线程的引用被持有,才能正常使用。
当创建了一个新的线程后,就可以像主线程那样来使用它。
lua_xmove(F, T, n)可以在两个栈之间移动lua值。它会从F中弹出n个元素并压入T中
使用多线程的主要目的是实现协同程序。......
lua_resume(Lua_State *L, int narg);
narg指定参数的个数
lua_resume可以启动以一个协同程序类似lua_call--压入函数--压入参数--压入参数数量
如果正在运行的函数交出[yield]了控制权lua_resume就会返回一个特殊的代码LUA_YIELD并将线程置于一个可以被再次恢复执行的状态
通常以一个Lua函数作为一个协同程序来启动这个Lua函数可以调用其他Lua函数。
一个C函数只有在返回时才会交出控制权。因此C函数实际上是不会停止自身执行的。但如果调用者是一个lua函数那么如果C函数调用lua_yield就可以挂起lua的调用者。
---------------------------------------Lua状态---------------------------------------------------
每次调用luaL_newstate都会创建一个新的lua状态。不同的lua状态时各自完全独立的,他们之间不共享任何数据。不能之间沟通需要辅助代码完成---
----------------------------------------该节有些复杂---以后看吧
------------------------第31章 内存管理 -----------------------------
Lua对其内存使用具有严格控制当关闭一个Lua状态时Lua会显示地释放它的所有内存。
luaL_newstate会一个默认的分配函数来创建lua状态malloc-realloc-free
若要控制lua的内存分配则使用原始lua_newstate
==========================================================================================
From example...
Lua中一般以_开头的变量作为特殊变量
而_却经常作为 dummy variable
a="single 'quoted' string and double \"quoted\" string inside"b='single \'quoted\' string and double "quoted" string inside'
swap two variables------------------------print(a,b)a,b=b,aprint(a,b)------------------------
print(address.StreetNumber, address["AptNumber"])
-- Conditional assignment.-- value = test and x or y
a=1b=(a==1) and "one" or "not one"print(b)
-- is equivalent toa=1if a==1 then
b = "one"else
b = "not one"end
=====================================================
for a=1,6,3 do io.write(a.." ")end
阅读(...) 评论()

我要回帖

更多关于 alter talbe 的文章

 

随机推荐