lua语法学习笔记

最近开始学习cocos2d,也随便学习一下lua语言的简单使用。一些基本的不同:

  1. lua是..连接字符串,php是.连接字符串,javascript和python和C++都是+号连接字符串
  2. lua是==和~=进行比较,其他语言大都是==和!=进行比较
  3. lua是从1开始计数的,其他语言大都以0开始计数

交互模式使用lua语言:

lua/luajit$ ./LuaJIT-2.0.1/src/luajit -i
LuaJIT 2.0.1 -- Copyright (C) 2005-2013 Mike Pall. http://luajit.org/
JIT: ON CMOV SSE2 SSE3 SSE4.1 fold cse dce fwd dse narrow loop abc sink fuse
> a={'abc', 'def'}
> print(a[1])
abc
> print(a[0])
nil

冒号与点

lua里一切都是表,即{},对应到底层就是hash表。点就是访问表中元素,不限类型, 冒号是访问表中函数,且表自身作为参数列表的第一个参数。对应到面向对象编程,点可以简单理解为静态成员函数,冒号可以简单理解为类成员函数。

> a = {}
> function a:output(...) print(self, ...) end
> a:output(1,2,3)
table: 0x40d45bd8       1       2       3
> a.output(a, 1,2,3)
table: 0x40d45bd8       1       2       3
> a.output(self, 1,2,3)
nil     1       2       3

上面的output被以两种方法访问了。注意,保留字self只有在函数定义时才有用。

在quick cocos2d中,有这么个函数:

function handler(target, method)
    return function(...)
        return method(target, ...)
    end 
end

这样在类中给一个变量赋一个成员函数时,可以写成:

local onTouch = handler(self, self.doTouch)

其实跟

local onTouch = self:doTouch

一个意思,但是感觉前者更顺眼一些。

定义一个表

由于懂点python,又懂点javascript和css,所以定义一个表都时常写错。当然也跟lua里诡异风格相关。

a = { 
    name = 'wangyang',
    age = 129 
}

或者

a = { 
    ['name'] = 'wangyang',
    ['age'] = 129 
}

别的语言里都是标准json格式,lua有点不伦不类。第二种写法完全是为了方便变量名以非字符和下划线打头设计,但加引号也就够了, 为嘛还要加中括号,表示费解,估计是为了加快解析,跟数组定义绝对区分开来:

a = {
    'name',
    'age'
}

当然访问的时候,也有两方法,a.namea['name']

有break和return,但没有continue

Lua就是这么简洁,连continue都省略掉了,但据说lua 5.2版本里加入了goto保留字来解决continue缺失的问题。 当然其实没有continue也不是什么大的问题,加一层if条件判断就行了,当然会导致代码缩进更深一层。

还一点很不一样,就是return只能是一个代码块的最后一句。比如:

function output()
    return
    print('hello world')
end

只能写成:

function output()
    do return end
    print('hello world')
end

最明确的判断语句

真假判断非常明确:在if while等判断语句中,只有false和nil是假,其他都是真,包括空串和数字0

相等判断非常明确:table, userdata, functions三种类型只有是同一个内存地址时才相等,相当于其他语言里的===

如下代码:

local baba = {}
if baba == {} then
    print('equal')
else
    print('not equal')
end 

会输出not equal

再如代码:

a = {}; a.x = 1; a.y = 0
b = {}; b.x = 1; b.y = 0
c = a

其结果是a~=b,但a==c

值得特别注意的for循环

lua的for循环语句有很多坑爹之处。例如:

for i=1,f(x) do print(i) end

i尽管没有local修饰,但是局部变量,只在循环里可见,如果循环外需要i的值,那么就在循环外定义一个变量,然后在循环中将i值赋给该变量。

f(x)只会被调用一次,循环次数在循环开始前就已经确定了,不会再改变,例如:

> s={"a", "b", "c", "d"}
> for i = 1, #s do print(i, s[i]) if i == 3 then table.remove(s, 3) end end
1       a
2       b
3       c
4       nil

在循环内i能改变,但不会影响到循环的次数。如下面的代码只会运行10次:

for i = 1,10 do
    i = i -1 
    print(i)
end

for循环中有一个do,其实do和end才是配对的,比较容易写掉。循环范围中1,10,是[1,10],即闭区间。循环还可以控制递增值,逆序循环如:

for i=10,1,-1 do print(i) end

由于有以上很多注意点,一个完备的删除函数应该这么写:

function table.removeItem(list, item, removeAll)
    local rmCount = 0
    for i = 1, #list do
        if list[i - rmCount] == item then
            table.remove(list, i - rmCount)
            if removeAll then
                rmCount = rmCount + 1
            else
                break
            end
        end
    end
end

for循环还有如下形式,跟python里的for in语法有点像:

for i,v in ipairs(a) do print(v) end
for k in pairs(t) do print(k) end

上面写法跟如下代码等效:

table.foreachi(a, print)
table.foreach(t, function(k,v) print(k) end)

package控制lua文件的加载

-- 预加载列表
package.preload
-- 加载器,可以定制查找lua模块的方式
package.loaders
-- 已经加载列表,置nil即可卸载已加载模块
package.loaded
-- lua文件查找路径,例如:./?.lua;/usr/lib/?.lua;xxx/?.lua
package.path
-- c模块查找路径
package.cpath
package.seeall
-- 加载c模块
package.loadlib()

常用函数

collectgarbage(opt [, arg])

功能:是垃圾收集器的通用接口,用于操作垃圾收集器
参数:
opt:操作方法标志
"Stop": 停止垃圾收集器
"Restart": 重启垃圾收集器
"Collect": 执行一次全垃圾收集循环
"Count": 返回当前Lua中使用的内存量(以KB为单位)
"Step": 单步执行一个垃圾收集. 步长 "Size" 由参数arg指定(大型的值需要多步才能完成),如果要准确指定步长,需要多次实验以达最优效果。如果步长完成一次收集循环,将返回True
"Setpause": 设置arg/100的值作为暂定收集的时长
"Setstepmul": 设置arg/100的值,作为步长的增幅(即新步长=旧步长*arg/100)

dofile(filename)

功能:打开并且执行一个lua块,当忽略参数filename时,将执行标准输入设备(stdin)的内容。返回所有块的返回值。当发生错误时,dofile将错误反射给调用者.
dofile不能在保护模式下运行

error(message [, level])

功能:终止正在执行的函数,并返回message的内容作为错误信息(error函数永远都不会返回)
通常情况下,error会附加一些错误位置的信息到message头部.
Level参数指示获得错误的位置
Level=1[默认]:为调用error位置(文件+行号)
Level=2:指出哪个调用error的函数的函数
Level=0:不添加错误位置信息

_G全局环境表(全局变量)

功能:记录全局环境的变量值的表_G._G = _G

getfenv(f)

功能:返回函数f的当前环境表
参数:f可以为函数或调用栈的级别,级别1[默认]为当前的函数,级别0或其它值将返回全局环境_G

getmetatable(object)

功能:返回指定对象的元表(若object的元表.__metatable项有值,则返回object的元表.__metatable的值),当object没有元表时将返回nil

ipairs (t)

功能:返回三个值 迭代函数、表、0
多用于穷举表的键名和键值对
如:

for i,v in ipairs(t) do 
    ...
end

每次循环将索引赋级i,键值赋给v
注:本函数只能用于以数字索引访问的表 如:t={"1","cash"}

load(func [, chunkname])

功能:装载一个块中的函数,每次调用func将返回一个连接前一结的字串,在块结尾处将返回nil
当没有发生错误时,将返回一个编译完成的块作为函数,否则返回nil加上错误信息,此函数的环境为全局环境
chunkname用于错误和调试信息

loadfile([filename])

功能:与load类似,但装载的是文件或当没有指定filename时装载标准输入(stdin)的内容

loadstring(string [, chunkname])

功能:与load类似,但装载的内容是一个字串
如:assert(loadstring(s))()

next(table [, index])

功能:允许程序遍历表中的每一个字段,返回下一索引和该索引的值。
参数: table:要遍历的表
index:要返回的索引的前一索中的号,当index为nil[]时,将返回第一个索引的值,当索引号为最后一个索引或表为空时将返回nil
注:可以用next(t)来检测表是否为空(此函数只能用于以数字索引的表与ipairs相类似)

ipairs (t)

功能:返回三个值 next函数、表、0
多用于穷举表的键名和键值对
如:

for n,v in pairs(t) do 
    ...
end

每次循环将索引赋级i,键值赋给v
注:本函数只能用于以键名索引访问的表 如:t={id="1",name="cash"}

pcall(f, arg1, ···)

功能:在保护模式下调用函数(即发生的错误将不会反射给调用者)
当调用函数成功能返回true,失败时将返回false加错误信息

print(···)

功能:简单的以tostring方式格式化输出参数的内容

rawequal(v1, v2)

功能:检测v1是否等于v2,此函数不会调用任何元表的方法

rawget(table, index)

功能:获取表中指定索引的值,此函数不会调用任何元表的方法,成功返回相应的值,当索引不存在时返回nil
注:本函数只能用于以数字索引访问的表 如:t={"1","cash"}

rawset(table, index, value)

功能:设置表中指定索引的值,此函数不会调用任何元表的方法,此函数将返回table

select(index, ···)

功能:当index为数字将返回所有index大于index的参数:如:select(2,"a","b") 返回"b"
当index为"#",则返回参数的总个数(不包括index)

setfenv(f, table)

功能:设置函数f的环境表为table
参数:f可以为函数或调用栈的级别,级别1[默认]为当前的函数,级别0将设置当前线程的环境表

setmetatable(table, metatable)

功能:为指定的table设置元表metatable,如果metatable为nil则取消table的元表,当metatable有__metatable字段时,将触发错误
注:只能为LUA_TTABLE 表类型指定元表

tonumber(e [, base])

功能:尝试将参数e转换为数字,当不能转换时返回nil
base(2~36)指出参数e当前使用的进制,默认为10进制,如tonumber(11,2)=3

tostring(e)

功能:将参数e转换为字符串,此函数将会触发元表的__tostring事件

type(v)

功能:返回参数的类型名("nil","number", "string", "boolean", "table", "function", "thread", "userdata")

unpack(list [, i [, j]])

功能:返回指定表的索引的值,i为起始索引,j为结束索引
注:本函数只能用于以数字索引访问的表,否则只会返回nil 如:t={"1","cash"}

xpcall(f, err)

功能:与pcall类似,在保护模式下调用函数(即发生的错误将不会反射给调用者)
但可指定一个新的错误处理函数句柄
当调用函数成功能返回true,失败时将返回false加err返回的结果

发表于 2014年05月27日 10:55   评论:0   阅读:2460  



回到顶部

首页 | 关于我 | 关于本站 | 站内留言 | rss
python logo   django logo   tornado logo