Linux | c&cpp | Email | github | QQ群:425043908 关注本站

itarticle.cc

您现在的位置是:网站首页 -> 后端开发 文章内容

lua 语法简单介绍(元表,点,冒号,self)-itarticl.cc-IT技术类文章记录&分享

发布时间: 9年前后端开发 130人已围观返回

一、数组

在lua中通过整数下标访问表中的元素即可简单的实现数组。并且数组不必事先指定大小,大小可以随需要动态的增长。

a = {}

for i = 1,100 do

a[i] = 0

end

print("The length of array 'a' is " .. #a)

squares = {1, 4, 9, 16, 25}

print("The length of array 'a' is " .. #squares)

在Lua中习惯上数组的下表从1开始,Lua的标准库与此习惯保持一致,因此如果你的数组下标也是从1开始你就可以直接使用标准库的函数,否则就无法直接使用。


二、二维数组

Lua中主要有两种表示矩阵的方法,第一种是用数组的数组表示。也就是说一个表的元素是另一个表。

local N = 3

local M = 3

mt = {}

for i = 1,N do

mt[i] = {}

for j = 1,M do

mt[i][j] = i * j

end

end


mt = {}

for i = 1, N do

for j = 1, M do

mt[(i - 1) * M + j] = i * j

end

end

三、链表

Lua中用tables很容易实现链表,每一个节点是一个table,指针是这个表的一个域,并且指向另一个节点(table)。例如,要实现一个只有两个域:值和指针的基本链表,代码如下:

list = nil

for i = 1, 10 do

list = { next = list ,value = i}

end

local l = list

while l do

--print(l.value)

l = l.next

end


四、集合

在Lua中用table实现集合是非常简单的,见如下代码:

reserved = {

["while"] = true, ["end"] = true,

["function"] = true, ["local"] = true,

}

for k,v in pairs(reserved) do

print(k,"->",v)

end


五.LUA元方法

__add(a, b) --加法

__sub(a, b) --减法

__mul(a, b) --乘法

__div(a, b) --除法

__mod(a, b) --取模

__pow(a, b) --乘幂

__unm(a) --相反数

__concat(a, b) --连接

__len(a) --长度

__eq(a, b) --相等

__lt(a, b) --小于

__le(a, b) --小于等于

__index(a, b) --索引查询

__newindex(a, b, c) --索引更新(PS:不懂的话,后面会有讲)

__call(a, ...) --执行方法调用,即:abc(a,b)调用,如果把__call = new 则调用 new函数

__tostring(a) --字符串输出

__metatable --保护元表


六.__index 元方法(这一点比较重要)

在谈及Lua中的__index,__newindex,rawget和rawset前,需要理解Lua中的元表这个概念。

零、元表的概念

对Lua中元表的解释: 元表可以改变表的行为模式。

这里举个例子:

Window = {}

Window.prototype = {x = 0 ,y = 0 ,width = 100 ,height = 100,}

Window.mt = {}


function Window.new(o)

setmetatable(o ,Window.mt)

return o

end


Window.mt.__index = Window.prototype

Window.mt.__newindex = function (table ,key ,value)

if key == "wangbin" then

rawset(table ,"wangbin" ,"yes,i am")

end

end


w = Window.new{x = 10 ,y = 20}

w.wangbin = "55"

print(w.wangbin)

然后,我们可以看到打印信息是:yes,i am

原本赋值的地方是w.wangbin = "55",但是结果却是 yes,i am。

这里就改变了元表的行为模式

使用getmetatable和setmetatable来查看和设定table(表)的metatable(元表) ,setmetatable会返回它的第一个参数,可以作连续赋值,

一、__index的理解

__index是:当你通过键来访问table的时候,如果这个键没有值,那么Lua就会寻找该table的metatable(假定有metatable)中的__index键。如果__index包含一个表格,Lua会在表格中查找相应的键,如果__index包含一个函数的话,Lua就会调用那个函数,table和键会作为参数传递给函数,

Windows = {} -- 创建一个命名空间

-- 创建默认值表

Windows.default = {x = 0, y = 0, width = 100, height = 100, color = {r = 255, g = 255, b = 255}}

Windows.mt = {} -- 创建元表

-- 声明构造函数

function Windows.new(o)

setmetatable(o, Windows.mt)

return o

end

-- 定义__index元方法

Windows.mt.__index = function (table, key)

return Windows.default[key]

end

local win = Windows.new({x = 10, y = 10})

print(win.x) -- >10 访问自身已经拥有的值

print(win.width) -- >100 访问default表中的值

print(win.color.r) -- >255 访问default表中的值

根据上面代码的输出,结合上面说的那三步,我们再来看看,print(win.x)时,由于win变量本身就拥有x字段,所以就直接打印了其自身拥有的字段的值;print(win.width),由于win变量本身没有width字段,那么就去查找是否拥有元表,元表中是否有__index对应的元方法,由于存在__index元方法,返回了default表中的width字段的值,print(win.color.r)也是同样的道理。

二、__newindex的理解

__newindex:当给你的表中不存在的值进行赋值时,lua解释器则会寻找__newindex元方法,发现存在该方法,则执行该方法进行赋值,注意,是使用rawset来进行赋值,至于原因,后面会讲到。

Window.mt = {}

function Window.new(o)

setmetatable(o ,Window.mt)

return o

end

Window.mt.__index = function (t ,key)

return 1000

end

Window.mt.__newindex = function (table ,key ,value)

if key == "wangbin" then

rawset(table ,"wangbin" ,"yes,i am")

end

end

w = Window.new{x = 10 ,y = 20}

w.wangbin = "55"

print(w.wangbin)

ok,这里的打印结果是:yes,i am。w这个表里本来没有wangbin这个元素的,我们重写了元表中__newindex,并在__newindex方法中重新进行赋值操作,然后,我们对这个本不存在的原色w.wangbin进行赋值时,执行__newindex方法的赋值操作,最后,打印结果便是:yes,i am

三、rawget和rawset的理解

rawget是为了绕过__index而出现的,直接点,就是让__index方法的重写无效。(我这里用到"重写"二字,可能不太对,希望能得到纠正)

Window = {}

Window.prototype = {x = 0 ,y = 0 ,width = 100 ,height = 100,}

Window.mt = {}

function Window.new(o)

setmetatable(o ,Window.mt)

return o

end

Window.mt.__index = function (t ,key)

return 1000

end

Window.mt.__newindex = function (table ,key ,value)

if key == "wangbin" then

rawset(table ,"wangbin" ,"yes,i am")

end

end

w = Window.new{x = 10 ,y = 20}

print(rawget(w ,w.wangbin))

打印结果是:nil。这里的元表中__index函数就不再起作用了。

但是rawset呢,起什么作用呢?我们再来运行一段代码。

Window = {}

Window.prototype = {x = 0 ,y = 0 ,width = 100 ,height = 100,}

Window.mt = {}

function Window.new(o)

setmetatable(o ,Window.mt)

return o

end

Window.mt.__index = function (t ,key)

return 1000

end

Window.mt.__newindex = function (table ,key ,value)

table.key = "yes,i am"

end

w = Window.new{x = 10 ,y = 20}

w.wangbin = "55"

然后我们的程序就stack overflow了。可见,程序陷入了死循环。因为w.wangbin这个元素本来就不存在表中,然后这里不断执行进入__newindex,陷入了死循环。


总结:

当你通过键来访问table的时候,如果这个键没有值,那么Lua就会寻找该table的metatable(假定有metatable)中的__index键。如果__index包含一个表格,Lua会在表格中查找相应的键.如果__index包含一个函数的话,Lua就会调用那个函数,table和键会作为参数传递给函数.

__newindex 与 __index 一样, 只不过 __newindex 是 用于按键赋值的时候,需要使用rawget和rawset以避免死循环


LUA查找一个表元素的规则:

总结一下Lua查找一个表元素时的规则,其实就是如下3个步骤:

1.在表中查找,如果找到,返回该元素,找不到则继续

2.判断该表是否有元表(操作指南),如果没有元表,返回nil,有元表则继续

3.判断元表有没有__index方法,如果__index方法为nil,则返回nil;如果__index方法是一个表,则重复1、2、3;如果__index方法是一个函数,则返回该函数的返回值


保护元表:

在Lua中,函数setmetatable和getmetatable函数会用到元表中的一个字段,用于保护元表,该字段是__metatable。当我们想要保护集合的元表,是用户既不能看也不能修改集合的元表,那么就需要使用__metatable字段了;当设置了该字段时,getmetatable就会返回这个字段的值,而setmetatable则会引发一个错误;


lua setmetatable 会先判断 __metatable 是否有值,与__index 没有关系


七.点,冒号与self

lua编程中,经常遇到函数的定义和调用,有时候用点号调用,有时候用冒号调用,这里简单的说明一下原理。如:

点号调用:

-- 点号定义和点号调用:

girl = {money = 200}

function girl.goToMarket(girl ,someMoney)

girl.money = girl.money - someMoney

end

girl.goToMarket(girl ,100)

print(girl.money)

引用参数self:

-- 参数self指向调用者自身(类似于c++里的this 指向当前类)

girl = {money = 200}

function girl.goToMarket(self ,someMoney)

self.money = self.money - someMoney

end

girl.goToMarket(girl, 100)

print(girl.money)

冒号调用:

-- 冒号定义和冒号调用:

girl = {money = 200}

function girl:goToMarket(someMoney)

self.money = self.money - someMoney

end

girl:goToMarket(100)

print(girl.money)

冒号定义和冒号调用其实跟上面的效果一样,只是把第一个隐藏参数省略了,而该参数self指向调用者自身。

总结:冒号只是起了省略第一个参数self的作用,该self指向调用者本身,并没有其他特殊的地方


冒号主要用于对象的函数调用,在函数内部使用self+点号来引用对象内部的成员

LUA对象的子对象是用点号访问的,函数也是LUA对象的一个子对象,直接用点号访问的意思是设置这个函数,即定义

用冒号则是调用这个函数,执行这个函数的操作

发布时间: 9年前后端开发130人已围观返回回到顶端

很赞哦! (1)

文章评论

  • 请先说点什么
    热门评论
    129人参与,0条评论

站点信息

  • 建站时间:2016-04-01
  • 文章统计:728条
  • 文章评论:82条
  • QQ群二维码:扫描二维码,互相交流