微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

lua 笔记

2014.6.12

第一章:开始

1.2词法规范

下划线家一个大写字母或者多个大写字母的标志,lua将这类标识符留作特殊用途,哑变量使用。哑变量的百度词条如下:哑变量又被称为虚设变量,用以反映质的属性一个人工变量,是量化的自变,通常取值为0或者1。

表示未懂,准备留下具体例子。


2.类型与值

2.5table(表)

文中说,lua中table的本质是对象,而对象的意义一般而言内存中具有类型的区域,这是C++中对象的含义。

Lua不会产生table的副本或者创造新的table,table是不能被声明的,他直接由构造表达式生成

table永远是匿名的,一个持有table的变量鱼table之间没有固定的关联性。也就是更改了table的引用,同时改变了table本身。

区别对待a.x 与 a[x],前者表示a["x"],儿后者以变量x的值访问table。

table将nil作为数组结尾的标志。

table初始化中存在不能使用负数索引,不能使用运算符作为记录的字段名。但是在方括号中可以使用这样的方式初始化。


第五章:函数

5.1多重返回值

return中圆括号与函数返回几个值无关,其他地方强制返回一个值。

5.2变长参数

select()函数返回变长参数的长度,select(“#” ,....)返回所有变长参数的总数,包括nil.

老版本中,存的是arg,每次调用都会新建一个table。


第六章:深入函数

第一类值:表示函数与其他传统类型的值(例如:数字或者字符串)具有同样的权利。

词法域:一个函数嵌套在另一个函数中,内部函数可以访问外部函数的变量。

语法糖:指的是计算机中添加某种语法对语言功能并没有什么帮助,但是方便程序员的使用,通常来说使用语法糖能够增加程序的可读性,从而减少程序出错的机会。

6.1闭合函数

作为第一类值使用的函数,同时能使用词法域,例如:非局部的变量用法。同时非局部变量不会被释放的主要原因可能在于函数被返回,增加了引用。

6.2非全局函数

迭代函数

local fact = function (n)
	if n == 0 then return 1
		else return n * fact(n - 1)
	end
end

fact(5)

报错,因为fact并未定义完全。但是,下面代码

function fact(n)
	if n == 0 then return 1
		else return n * fact(n - 1)
	end
end

fact(5)
不会报错。调用了fact 并不是函数本身。但是具体的还是不懂内部原因,个人看来fact函数同样是没有定义完全。

后文提到局部函数的定义 local function foo (<参数>) <函数体>end

等价于

loca foo

foo = function (<参数>)<函数体>end

解释就比较通畅了。

这种技巧对于间接递归无用,必须使用前向声明。

6.3正确的尾调用

类似于goto很奇特的一个东西,不会保存任何该函数的栈信息。也就意味着不会耗费栈空间。

调用的判断准则:一个函数调用完另一个函数后,是否就无所事事需要做了。


第七章:迭代器与泛型for

7.2泛型for的语法

for结构的三个变量迭代函数f,恒定状态s,控制变量a。 a1= f(s,a0)

7.3无状态迭代器

自身不不保存任何状态的迭代器。需要具体例子说明为ipairs函数

local function iter(a,i)
	i = i + 1
	local v = a[i]
	if v then
		return i,v
	end
end

function  ipair(a)
	return iter,a,0
end

test = {1,2,3 }

for i,v in ipair(test) do
	print(i,v)
end

这个例子很好的说明for原理,ipaires返回的是iter 作为迭代函数,a作为恒定状态,0作为控制变量初始值。i和v为多值返回值,状态变量为i,第一个为状态变量。

无状态迭代器避免创建新的闭包,没有使用非局部变量upvalue。

7.4复杂状态迭代器

两种解决方案:1.闭包。2.table。通常忽略控制变量。

举例:

local iterator

function allword()
	local state = {line = io.read(),pos = 1}
	return iterator,state
end

function iterator(state)
	while state.line do
		-- something return state
	end
	return nil
end


闭包state,同时使用table存储多个数据。


第八章:编译、执行与错误

8.1编译

loadstring总是在全局环境中编译字符串。表达式求值需要添加return构成一条语句。并且将独立的程序块视为一个匿名函数函数体,并且具有可变长实参。

函数定义是赋值操作,在运行的时候才完成操作。

8.3错误

调用错误可以指定层级,error("",numb),并且在xpcall中可以定义错误处理函数,debug.traceback与debug.debug。


第十三章:元表与元方法

13.4table访问

其中建立私有索引这块个人有点看不懂,自己动手实现了一下,发现里面问题挺多的。

首先是使用表引用表,访问的问题。

key = {"test"}
mt = {key}


print(mt[1][1]) -->test

无法通过mt[key]访问,等价于 mt = {{"test"}}

key = {"test"}
mt = {}
mt[key] = "testagain"

print(mt[key])
这样就不能再通过mt[1]进行访问了,只能通过[key],如果key为私有,外部不能进行访问。直接print(key)结果为地址。
现在也就能明白何为私有索引。相关链接如下。

http://hi.baidu.com/tanglewish/item/83184b10c5e59925f7625c28


第十五章:模块与包

15.1require函数

关于函数require的具体的运行过程,对其原理的理解很重要。

15.2编写模块的基本方法

在实际运用在需要不断的体认,其中三种方法

第一种:直接定义模块,首先,必须显示的将模块名放在每个函数定义中,其次,在一个函数调用一个函数,需要限定调用函数名称

第二种:使用一个固定的局部名称。只是不再依赖模块名。

第三种:将模块直接赋给package.loaded。

15.3使用环境

使用环境后,调用同一模块是不需要前缀,会从环境中自动获取添加。导出函数调用一个私有函数没有区别。

使用环境,带来的问题是无法访问前一个环境变量。解决方案如下。

第一种:继承。第二种:声明一个局部变量,此时必须在所有全局变量添加G。第三种更加正规,将要使用的函数和模块声明为局部变量。

15.4module函数

项目中使用会很多。等价于:

local  modname = ....
local M = {}
_G[modname] = M
package.loaded[modname] = M

setfenv(1,M)
不是很明白 G这段代码。周一找组长。个人猜想,是因为后面没有return后,需要这个放在全局变量中,在其他模块中使用能直接获取modname,而package.loaded列表不能只是能表示这个模块被加载,因为在没有return的情况下,require会返回loaded中的值,具体的细看require函数

15.5子模块和包

require中目录分隔符值得注意一下。

module加载子模块时会添加显示支持,module(a,b,c)会将环境变量添加进入,包中的子模块没有显式的联系,也就是不会认加载了。例如:require(a.b)并不会加载a。


第十六章:面对对象编程

16.2继承

实现继承的代码

        setMetatable(o,self)
	self.__index = self
子类的元表是父类,子类中查找不到函数时,index访问父类的self。

16.3多重继承

多重继承的原理需要理解清楚,这对于元表的使用有帮助。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐