Lua语法常见坑点和注意事项

概述

虽然已经很多年没有使用过Lua了,但是在司内的知识分享中,又捡了起来。这里总结了自己之前使用过程中遇到的一些奇怪的问题,以及重要或者奇怪的使用方法。

而且不同版本的Lua,表现形式都不同。这里推荐在练习时使用zerobrane studio,可以很方便地切换Lua的版本。

关于多行注释的安全问题

如果直接使用默认的–[[和–]]来进行多行注释的时候,如果遇到table包table的情况会直接结束注释:

--[[
a = [];
b = [a];
a[b[1]]
a = 1
--]]

可以使用另一种方法来进行多行注释,避免这个问题:

--[=[
a = [];
b = [a];
a[b[1]]
a = 1
]=]

当然,最安全的方法还是使用IDE的快捷键进行注释。IDE会在每行的前面加单行注释,避免错误的发生。

多行字符串安全问题

多行字符串,也会出现类似于上面的情况:

str = 
[[
话说
这个东西
好像打印不出来
就是这个
table[table[idx]]
咋办啊
]]
print(str)

运算符相关

#运算符

#运算符取的是最大索引的值,如果删除了部分中间的值,获得的结果不会改变:

tb_a = {1, 2, 3}
print (#tb_a)
tb_a[2] = nil
print (#tb_a)

但是这种情况仅限于Lua 5.1 ,Lua5.3和Lua5.4结果是1。

and or

模拟三目运算符的and…or…,在第二个参数为false时,始终返回c,会出现问题:

a = true
print (a and false or true)

输出结果会是true 而不是三目运算符应该返回的false。
这时候,可以将三目运算符的后面两个部分转换成table,运算结束后再取第一个元素,即可实现:

a = true
b = (a and {false} or {true})[1]
if b then
	print("true")
else
	print("false")
end

迭代器相关

自定义迭代器

for 变量列表 in 迭代函数, 状态变量, 控制变量 do
    -- 循环体
end

自定义无状态迭代器

function square(iteratorMaxCount, currentNumber)
    if currentNumber < iteratorMaxCount then
        currentNumber = currentNumber + 1
        return currentNumber, currentNumber * currentNumber
    end
end
for i, n in square, 3, 0
do
    print(i, n)
end

自定义多状态迭代器

多个状态可以存放在table,因此只需要一个参数即可:

array = {"Google", "Csdn"}
function elementIterator (collection)
    local index = 0
    local count = #collection
    -- 闭包函数
    return function ()
        index = index + 1
        if index <= count then
            --  返回迭代器的当前元素
            return collection[index]
        end
    end
end
for element in elementIterator(array) do
    print(element)
end

循环时的goto语句

可以使用goto语句来实现continue:

for i=1, 3 do
    if i <= 2 then
        print(i, "yes continue")
        goto continue
    end
    print(i, " no continue")
    ::continue::
    print([[i'm end]])
end

元表

Lua可以通过设置元表,定义元方法的方式,改变table的一些行为:

index

index元方法,可以修改按索引取值的逻辑。
若index内容是一个表的话,如果table里没有值,会从元表中对应的索引去取:

t_table = setmetatable({k1 = "v1"}, {__index = {k2 = "v2"}})
print(t_table["k1"])
print(t_table["k2"])
t_table["k2"] = "v3"
print(t_table["k2"])
--[[
输出是:
v1
v2
v3
--]]

若__index内容是一个函数,则可以定义返回逻辑:

t_table = setmetatable({}, {__index =
	function(t_table, key)
		if key == 1 then
			return "true"
		else
			return "false"
		end
	end
})
print(t_table[1])
print(t_table[2])
print(t_table[3])
t_table = {1, 2, 3}
print(t_table[1])
print(t_table[2])
print(t_table[3])
--[[
输出是:
true
false
false
1
2
3
--]]

__newindex

__newindex元方法,可以修改追加索引时的逻辑

t_table = setmetatable({k1 = "v1"}, {
	__newindex =
	function(t_table, key, value)
		rawset(t_table, key, "\"v" .. value .. "\"")
	end
})
t_table["k2"] = 2
print(t_table["k1"])
print(t_table["k2"])
--[[
输出是:
v1
"v2"
--]]

add和tostring

t_table = setmetatable({1, 2, 3}, {__add =
	function(t_table, data)
		t_table[#t_table + 1] = data
		return t_table
	end,
	__tostring =
	function(t_table)
		local res = ""
		for _, v in pairs(t_table) do
			res = res .. v
		end
		return res
	end
})
print(t_table)
print(t_table + 4)
--[[
输出:
123
1234
--]]

其它运算符对应原表

元表运算符
add+
sub-
mul*
div/
mod%
unm-(相反数)
concat
eq==
lt<
le<=

注意事项

需要注意的是,关系运算符,比较的两端,元表必须相同。如果只有一方有元表,另一方没有,又或者是两方拥有不同的元表,会导致比较报错:

a_metatable =
{
	__gt = function(a_table, b_table)
		return a_table[1] > b_table[1]
	end,
	__lt = function(a_table, b_table)
		return a_table[1] < b_table[1]
	end
}
b_metatable =
{
	__gt = function(a_table, b_table)
		return b_table[1] > a_table[1]
	end,
	__lt = function(a_table, b_table)
		return b_table[1] < a_table[1]
	end
}
a_table = setmetatable({0}, a_metatable)
b_table = setmetatable({1}, b_metatable)
print(a_table<b_table)
--[[
报错内容是:
attempt to compare two table values
--]]

取反的重写

a_metatable =
{
	__unm = function(a_table)
		local _temp_table = {}
		for i = #a_table, 1, -1 do
			_temp_table[#a_table + 1 - i] = a_table[i]
		end
		return _temp_table
	end
}
p_metatable =
{
	__tostring =
	function(a_table)
		local res = ""
		for _, v in pairs(a_table) do
			res = res .. v
		end
		return res
	end
}
a_table = setmetatable({1, 2, 3}, a_metatable)
b_table = setmetatable(-a_table, p_metatable)
print(b_table)

__call

function_content =
{
	__call = function(a_table, a_data)
		print(a_data)
	end
}
func_print = setmetatable({}, function_content)
b = func_print(4)

协程的实现

function sleep(n)
   local t0 = os.clock()
   while os.clock() - t0 <= n do end
end
-- 这里的sleep会占用大量资源 正常逻辑不能使用
test_coroutine = coroutine.create(
	function()
		for i = 1, 10, 1 do
			print(i)
			sleep(0.1)
			coroutine.yield()
		end
	end
)
function do_cro(co)
	while(coroutine.status(co) ~="dead") do
		coroutine.resume(co)
	end
end
do_cro(test_coroutine)

面向对象的table实现

用table实现了类与继承:

-- 类
-- 类管理器 
CClassManager = {}
function CClassManager.ctor(cls, ...)
  local this = {}
  setmetatable(this, cls)
  cls.__index = cls  -- 将元表的__index设为自身,访问表的属性不存在时会搜索元表
  cls.init(this, ...)
  return this
end
function CClassManager.VInit(self, ...)
end
function CClassManager.init(self, ...)
  self:VInit(...)
end
function CClassManager.dtor(cls)
  -- do sth
end
-- 通过继承实现的类的定义
ClassT = CClassManager:ctor()
function ClassT.VInit(self, word)
  self.word = word
end
function ClassT.say(self)
  print(self.word)
end
test = ClassT:ctor("B")
test:say()
test:dtor()
test:say()
  • 6
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值