0.lua的特性是什么?
1)lua是一种轻量级的脚本解释语言,在游戏开发过程中多用于实现需要进行热更新的逻辑
它用标准的c语言编写并以源代码的形式开放,编译后仅仅一百余k,可以很方便的嵌入到别的程序中
2)可扩展:lua提供了非常易于使用的扩展接口和机制,由宿主语言(通常是c或c++)提供这些功能,lua可以使用他们,就像是本来就内置的工能一样
其他特性:
1
)支持面向过程编程和函数式编程
2)自动内存管理,只提供一种通用类型的表,用它可以实现数组,哈希表,集合,对象
3)语言内置模式匹配,闭包,函数也可以看成一个值,提供多线程(协同程序,并非操作系统所支持的线程)支持
4)通过闭包和tabel可以很方便的支持面向对象编程所需要的一些关键的机制,比如数据抽象,虚函数,继承和重载等
1.关于lua中点号和冒号的区别?
①冒号定义成员函数相比点定义可以减少一个需要传入自身的参数,内部用self来访问自身;
②点调用冒号定义的函数时,需要多传入一个参数,传入的第二个参数开始才对应于原函数的参数列表,函数内部用到的self则变为对应于传入的第一个参数的普通变量,故传入的第一个参数应该当是调用者自身(当然如果函数内部并没有用到self则第一个参数随便传个什么都行);
③冒号调用点定义的函数时,原函数的第一个参数强制变为等同于self的变量,传入的参数从原参数的第二个参数开始才能一一对应上,因此通常这样调用都是会出错的(除非函数内部原本就把第一个参数在当self用...)。
故在Lua中成员函数的定义应该约定一种形式而不要点和冒号同时使用,不然调用者可能会不清楚该函数是否支持另一种方式的调用而增加出错的可能。
语法糖
1)定义方法的区别:(1)冒号定义方法,默认会接受self参数,而点号定义的时候,默认不接受self参数
冒号定义:
function class:test()
--这里会接受self参数,比如
print(self.a,self.b)
在这里self就是class对象本身,因此不会出错
end
(2)点号定义
function class.test() - -(self)
--点号定义时,默认不会接受self参数,因此在这里用self会出错,找不到全局变量self,当然如果你把self定义成了一个全局变量的话。。。那么你赢了。。
print(self.a,self.b)--报错,找不到全局变量self
end
2)调用方法的区别:冒号的调用方法会默认的将对象本身(self)传递给方法,而点号调用则不会
例1:冒号定义
function class:test()
print(self.a,self.b)
end
(1)冒号调用:class:test(),这时候在test方法是可以使用self的,因为默认会将self传递给test方法
(2)点号调用:class.test() - -(self),这时候在test方法中使用self就会报错了,因为self并没有被传递给test方法,那么要怎么在test方法中使用self呢?其实也简单,把class对象传递过去就好了,如:class.test(class)
例2:点号定义
function class.test()
print(self.a,self.b)
end
one day
lua的基本语法
1.列举出lua的基本数据类型(8种)
nil boolean string number usedata(用户类型,非脚本用户只能使用不能定义)
thread table function
2.lua中ipairs和pairs的区别?
pairs可以便利表中的所有的key
并且除了迭代器本身以及便利表中本身可以返回nil
但是ipairs不能返回nil,只能返回数字0,如果遇到nil便会退出,他只能 遍历到表中出现的第一个不是整数的key值
3.lua中的变量定义规则和c++一样都是大小写敏感的,以字母或下划线开头的,整体有字母下划线和数字组成,并且要注意lua中的关键字
全局变量不用声明,但是局部变量用local声明,删除全局变量直接将其设置为nil
单行注释:- -
多行注释:- -[[ ccc - -]]
转义字符:
4.如果你想将一个变量删除就将它赋值为空nil
关系运算符
>< >= <= == ~=(唯一一个和c++不同的)= (c++)!=
5.逻辑运算符
and =&& or=|| not=!
and的优先级比or高,c语言中的三元运算符a?b:c. 在lua中可以这样实现。
(a and b) or c
转换类型:tonumber()
链接字符串 .. 最好两边保留空格,这样不至于产生错误
6.lua中的三种循坏(while,for,repeat)
i=0
while i<10 do
i=i+1
print(i)
end
i=1
repeat
print(i)
i=i+1
until i>10
7.函数中的注意事项:
1)lua函数实参和形参的匹配和赋值语句类似,多余部分被忽略,缺少部分用nil补足
2)lua函数中,在return后列出要返回的值的列表即可返回多值
3)lua函数可以接受可变数目的参数,和c语言类似在函数参数列表中使用三点(…)表示函数有可变的参数,lua将函数的参数放在一个叫arg的表中,除了参数以外,表中还有一个域n表示参数的个数
8.闭合函数
一个函数加上该函数所需访问的所有“非局部的变量”
function count()
local i=0 - -非局部变量
return function()
i=i+1
return i
end
end
count函数返回另一个函数,并且另一个函数使用了count函数中的局部变量
***对于闭合函数而言,属于它的非局部变量,并不是在调用它的时候临时产生的,而是和它一起存在的,所以每次调用闭合函数,非局部变量的值都不会被重置
9.尾调用的好处?
尾调用的时候,该函数也就意味着结束了,不需要保存任何关于该函数的栈信息,因此可以拥有无数嵌套尾调用,尾调用主要用来实现状态机等操作
尾调用函数,面试有考到
function f(n, now)
if n <= 0 then
return now
end
return f(n - 1, now * n)
end
f(10000000000, 1)
—运行很久也不会溢出
迭代器和泛型for
闭合函数的存在也是实现迭代器的重要函数
TWO day
编译执行与错误
1)assert:断言方法,里有两个参数第一个是一个判断,第二个是一个判断不成立后的信息
不成立的话就会触发异常,成立继续走
2)pcall捕获错误代码
3)测试
--可以简化代码,让代码美观,并且会经常用于判断一些错误发生
function add(a,b )
-- if type(a)~='number' or type(b) ~= 'number' then
--如果条件表达式bu成立就会触发异常,成立会继续走
assert(type(a)=='number' and type(b)=='number','a,b不是数字')
-- error('a,b不是数字')
-- end
return a+b
end
-- add(10,'32')
--捕获错误代码,pcall
-- if pcall(add,10,'3') then
-- print("正常")
-- else
-- print("错误")
-- end
--pcall可以修改成
local status,err=pcall(add,10,'23')
print(status)
if status then
print("正常")
else
print(err)
end
2.请逐一说出require,loadfile,dofile的区别?
package.path = package.path .. ';../?.lua';
文件搜索路径
1
)loadfile:只编译不执行,就是只加载文件中的内容但是不会执行文件中的代码
2)dofile:即编译也会执行,就是加载文件的同时也会执行文件中的代码,并且会【重复执行】
3)require:即编译也执行,即加载文件的同时也会执行文件中的代码,但是只执行一次,即【执行一次】后保存已经加载的文件,不会重复加载
协同程序
3.协同程序有四种状态:挂起(suspended)运行(running)死亡(dead)正常(noemal)
4.协同程序中各个函数的意思?
coroutine.create(arg):根据一个函数创建一个协同程序,参数为一个函数
coroutine.resume(co):使协同从挂起变为运行(1)激活coroutine,也就是让协程函数开始运行;(2)唤醒yield,使挂起的协同接着上次的地方继续运行。该函数可以传入参数
resume有两个参数:协同程序。 可以传递给协同程序的函数的参数
有两个返回值:代表协同程序是否正确的执行。 yield抛出的信息/错误的信息
coroutine.status(co):查看协同状态
coroutine.yield():使正在运行的协同挂起,可以传入参数
5.协同程序的强大能力,还在于通过resume-yield来交换数据:
1)resume把参数传给程序(相当于函数的参数调用)
2)数据由yield传递给resume
3)resume的参数传递给yield
4)协同代码结束时的返回值,也会传给resume
并且协同程序的参数传递形式很灵活,在启动coroutine的时候,resume的函数参数是传给主程序的,在唤醒yield的时候,参数是传递给yield的
元表和元方法
lua元表
在lua table中我们可以访问对应的key来得到value值,但是无法直接对两个table进行操作,但是使用元表的话,允许我们改变table的行为,每个行为关联了对应的元方法
——call:表示在lua中调用一个值的时候调用
——tostring:表示用于修改表的输出行为的时候
6.请写出——index和——newindex的作用?
——index:用于查询,——newindex用于更新
——index:在访问到不存在的字段时,可以进行一些自定义的操作,查询顺序是:先从自身的表中进行查询,如果自身的表中没有该元素就会从元表中查询
用于在表中不存在的字段的时候触发
——newindex:如果自身的表中不存在需要更新的字段,则会更新元素中的字段,否则,会更新自身表中的字段
用于在添加新的字段的时候触发
作用:——newindex在访问不存在的字段的时候,可以进行一些自定义的操作或则是在给一些不存在的字段赋值的时候,可以进行一些监控操作
更新顺序:1)如果——newindex是一个函数,则会给table不存在的字段赋值时会调用
2)如果——newindex是一个table,则会在给table不存在的字段赋值时直接给——newindex的table赋值
7.请写出setmetatable和getmetatable的作用?
Setmetatable:两个参数,第一个是自定义的普通表,第二个是指定的元表,用于给一个表设置元表
Getmetatable:获得一个表的元表,参数为普通表,返回值为该表元表
注意事项:
1)如果第一个表有元表,那么执行元方法,操作的时候无论第二个表是否含有元表都以第一个表的元表为标准
2)如果第一个表没有元表,执行元方法,以第二表的元表为biaozhun
3)如果都没有元表或元方法,执行时会报错
lua全局环境
lua面向对象
8.lua是如何实现面向对象的?
1)使用function+table实现类
2)使用function创建类中的方法
3)使用table描述类中成员所拥有属性
4)使用setmetatable函数以及——index元方法实现继承
5)lua中可以实现函数的重写,即覆盖,但是不能重载
9.请写一个多值返回的函数?
Function foo2()
return ‘a’,’b’
end
10.请写一个可变参数的函数?
function g(a,b,…)
end
g(3,4,5,8) a=3,b=4,arg={5,8,n=2}
three day
lua的多重继承
闭包:通过调用含有一个内部函数加上该外部函数特有的外部局部变量upvalue)的外部函数(就是工厂)产生的一个实例函数
闭包组成:外部函数+外部函数创建的upvalue+内部函数(闭包函数)