Skip to main content

笔试

  1. 函数冒号与点的区别?

冒号的第一个参数默认为self,指向调用该函数的表。

  1. print(string.find(“hello hello”," hel"))的结果?

    6 9

  2. 普通全局变量和static全局变量的区别?

生存周期相同,作用域不同,普通全局变量可以作用于所有文件,extern声明即可,而static全局变量只能作用于当前文件。

  1. 解释下lua中的元表和元方法?

元表metetable : 允许该表table行为,行为关联元方法,类似一种“操作指南”,包含各种操作行为的解决方案!

元方法:当表执行某些操作失败的时候,操作指南里的元方法指导你的行为。

  1. index和newindex元方法的区别?

访问不存在的数据,由__index提供最终结果

__index元方法可以是一个函数,Lua语言就会以【表】和【不存在键】为参数调用该函数

__index元方法也可以是一个表,Lua语言就访问这个元表

  1. require,loadfile和dofile的区别?

在lua中我们引用其他模块的时候,可以使用三种方法:require,loadfile和dofile。

首先区分loadfile,loadfile只负责编译并不会执行模块代码,而require和dofile都会编译且执行。

知识点核心答案
闭包与Upvalue内层函数持有外层局部变量(upvalue),实现状态保持
**__index**查询不存在的键时触发,用于实现继承链
**__newindex**赋值不存在的键时触发,用于拦截赋值操作
深拷贝递归复制表的所有层级(需手动实现)

请写一个多值返回的函数

function foo2 () return 'a','b' end

请写一个可变参数的函数

function g (a, b, ...) end

g(3, 4, 5, 8) a=3, b=4, arg={5, 8; n=2}

Lua如何实现C#构造函数new方法

new传进的参数当做一个本地表, 元表本身Self作为元表,设置元方法,将其作为参数表o的元表,并返回出去 从而实现C# new构造函数。

调用new的时候,其实访问的是元表内容

function Class:(o) -- 传入self为Account
o = o or {}
self.__index = self --直接把表Class当做元表
setmetatable(o, self)
return o
end

local object = Class:new(o) --object变量可以访问元表

请写一个带有不定参数的lua函数,并输出所有的参数

function test( ... ) 
local args = { ... }
for k,v in pairs(args) do
print(k,v)
end
end

如下一段程序,请在TODO处插入代码,使后面对table新建值时提示错误,并使其无效

local table = setmetatable({}, {})
table.key = "iam key"
table.value = 123
print(table.key)
---- TODO:在这里插入你的代码

答案:

local mt = getmetatable(table) -- 获得table的元表
function mt:__newindex(key,value) -- 添加__newindex元方法
table[key] = nil
print("cannot create new property" .. key)
end

如何实现一个 Lua table的迭代器

-- 假设我们有一个table  
local myTable = {
a = 1,
b = 2,
c = 3
}

-- 自定义迭代器函数
-- 这个迭代器将按照插入顺序遍历table(注意:Lua table不保证顺序,这里仅为示例)
-- 但为了演示,我们假设或强制table有一个明确的顺序
local function iterator(table, keys)
local index = 0
return function()
index = index + 1
if index > #keys then
return nil -- 迭代结束
end
local key = keys[index]
return key, table[key] -- 返回键值对
end
end

-- 假设我们知道或能获取到table的键的顺序
local keys = {"a", "b", "c"} -- 在实际应用中,你可能需要动态获取这个顺序

-- 创建迭代器
local iter = iterator(myTable, keys)

-- 使用迭代器遍历table
for key, value in iter() do
print(key, value)
end

注意

上面的例子假设或强制了table的键有一个明确的顺序(通过keys数组),但在Lua中,普通的table并不保证键的插入顺序(Lua 5.2及以后版本引入了table.pack和table.unpack,但主要用于固定大小的数组,并不直接解决普通table的迭代顺序问题)。对于普通table,如果你需要按照特定的顺序迭代,你可能需要维护一个额外的数组来存储键的顺序。

使用内置的 pairs 函数 快捷返回迭代器

for key, value in pairs(myTable) do  
print(key, value)
end

pairs函数返回一个迭代器,它会遍历table中的所有键值对,但遍历的顺序取决于table的内部实现,可能不是插入顺序。

如果你需要按照插入顺序遍历,且你的Lua版本是5.3或更高,可以考虑使用table.move函数(虽然它本身不直接用于迭代,但可以用于在迭代前重新排序table的键)。

然而,对于大多数用途,简单地使用pairs可能就足够了。

实现替换字符串"abcdefgh"中的"abc"为"ddc"

string.gsub("abcdefgh","abc","ddc")

用Lua实现:提供一个功能,实现table只读

在Lua中,直接实现一个完全不可变的(只读)table是不可能的,因为Lua的table是动态数据结构,其元素可以在运行时被修改。但是,我们可以通过封装和元表(metatable)来模拟一个只读table的行为。

以下是一个简单的示例,展示了如何创建一个函数来返回一个“只读”的table。这个“只读”table实际上是通过一个代理table来实现的,该代理table会拦截所有尝试修改原始table的操作,并抛出错误或简单地忽略这些操作。

function createReadOnlyTable(originalTable)  
local readOnlyTable = {}
local metatable = {
__index = function(t, key)
return originalTable[key]
end,
__newindex = function(t, key, value)
error("Attempt to modify a read-only table", 2)
end
}

setmetatable(readOnlyTable, metatable)
return readOnlyTable
end

-- 示例使用
local original = {
a = 1,
b = 2,
c = 3
}

local readOnly = createReadOnlyTable(original)

print(readOnly.a) -- 输出: 1

-- 尝试修改只读table
readOnly.a = 10 -- 这将触发错误

-- 捕获并处理错误
try = function(func)
local ok, result = pcall(func)
if not ok then
print("Error:", result)
end
end

try(function() readOnly.a = 10 end) -- 输出: Error: Attempt to modify a read-only table

-- 原始table仍然可以修改
original.a = 10
print(readOnly.a) -- 输出: 10,因为只读table是通过原始table的索引来访问的

在这个示例中,createReadOnlyTable函数接受一个table作为参数,并返回一个新的table,这个新table通过元表(metatable)的__index__newindex方法被设置为只读。__index方法用于拦截对只读table的读取操作,并返回原始table中相应的值。__newindex方法用于拦截对只读table的写入操作,并抛出一个错误。

需要注意的是,虽然这个只读table的修改操作会被阻止,但原始table仍然可以被修改,这可能会影响通过只读table访问的数据。如果你需要完全隔离原始数据,你可能需要复制原始table的内容到一个新table中,并在这个新table上设置只读行为。

用Lua实现:生成10000000以内不重复的5555555个随机数

在Lua中生成大量不重复的随机数,特别是当数量接近或超过给定范围(如10000000)的一半时,需要一种有效的方法来确保随机数的唯一性。由于Lua标准库中的math.random()函数直接用于生成随机数可能会产生重复值,我们需要结合其他数据结构来确保唯一性。

一个常用的方法是使用集合(在Lua中通常使用表来模拟)来存储已经生成的随机数,并在每次生成新随机数时检查它是否已存在于集合中。然而,对于如此大量的随机数,这种方法可能会变得非常低效,因为随着集合的增长,检查新随机数是否已存在的成本也会增加。

一个更高效的方法是使用一种称为“洗牌算法”(Fisher-Yates Shuffle)的技术来随机化一个序列。对于这个问题,我们可以先创建一个包含1到10000000的整数序列,然后对这个序列进行随机洗牌,最后取前5555555个元素作为结果。

以下是一个Lua脚本的示例,展示了如何实现这一思路:

function shuffle(array)  
local n = #array
for i = n - 1, 1, -1 do
local j = math.random(i)
-- 交换 array[i] 和 array[j]
local temp = array[i]
array[i] = array[j]
array[j] = temp
end
end

function generateUniqueRandomNumbers(count, max)
if count > max then
error("Count cannot be greater than max")
end

-- 创建一个包含1到max的整数序列
local numbers = {}
for i = 1, max do
numbers[i] = i
end

-- 对序列进行随机洗牌
shuffle(numbers)

-- 返回前count个元素
return table.slice(numbers, 1, count)
end

-- Lua标准库中没有table.slice函数,这里提供一个简单的实现
function table.slice(tbl, first, last)
local sliced = {}
for i = first, last do
sliced[i - first + 1] = tbl[i]
end
return sliced
end

-- 生成5555555个不重复的随机数
local uniqueRandomNumbers = generateUniqueRandomNumbers(5555555, 10000000)

-- 打印前10个随机数作为示例
for i = 1, 10 do
print(uniqueRandomNumbers[i])
end