最近看到了一道号称腾讯最难的lua面试题:

研究了一下答案实现的过程,发现这题主要考察了元表和元方法、面向对象、环境这三个知识点,非常值得学习。题目如下:

function class(...)--TODO
end--TODO补充修改实现class方法
A =
class {name = string,age = int,foo = function()print('from A', name, age)end
}B =
class {__super = A,foo = function()print('from B', name, age)end
}local a = A()
a.name = 'hanmeimei'
a.age = 17
a:foo()local b = B()
b.name = 'lilei'
b.age = 18
b:foo()a.name = 20
a.age = '20'
b.foo = 'x'-- 输出-- from A hanmeimei 17
-- from B lilei 18
-- 类型不匹配:name 的类型是 string
-- 类型不匹配:age 的类型是 number
-- 函数不能赋值

(string和int必须修改,可替换为任意实值)

我觉得这题可以分为三步解决:

1、__newindex元方法实现错误赋值提示

输入:

输出:

解析:

1、若以类似函数的形式调用了一个值(table)时,则会调用它的__call元方法(此处a=A()而非a=A,因此会调用A的__call),因此用__call返回一个实例来完成a=A()的调用

2、对table中不存在的字段进行访问时,会调用__index;当对table中不存在的字段进行赋值时,会调用__newindex元。因此可构造一个不存在任何键值对的table,用data储存数据并赋值给__index,__newindex实现赋值类型检测并输出提示。

最初版本代码:

2、在全局环境中设置全局变量name和age实现foo()输出

输入:

输出:

解析:

1、foo()中对name和age的调用没有传入任何self参数,因此要在class中实现调用而不改变foo()结构,则可在访问foo()前将name和age放入全局环境中。由于访问foo()时会调用__index(),因此该步骤可在__index中实现。

2、设置全局环境变量时,由于lua 5.1之后的版本没有setfenv,因此需构造setfenv

代码实现:

setenv

__index

3、实现B()的继承

输入:

输出:

解析:

B的data继承自A,而非直接传入,因此改写local data = ...,将父类及...中的成员都复制到data中

代码实现:

经过以上主要步骤,稍作修改,即可实现最终要求。完整版代码:

function class(...)-- 返回的表类似“类”的定义local cls = {}-- 数据都存储在这里面,用作数据存储空间local data = {}-- 复制传入...的的成员。传入的...类似类定义中的成员列表。需要将父类,以及...内的成员都复制过来local function copyField(src, dest)-- 先复制父类if src['__super'] thenlocal superMeta = getmetatable(src['__super'])if superMeta and superMeta['__data'] thenfor k, v in pairs(superMeta['__data']) dodest[k] = vendendend-- 再复制子类,如果有重名,子类会覆盖父类for k, v in pairs(src) doif k ~= '__super' thendest[k] = vendendendcopyField(..., data)-- lua 5.1之后的版本没有setfenv,引入这段代码解决setfenv问题if not setfenv then-- based on http://lua-users.org/lists/lua-l/2010-06/msg00314.html-- this assumes f is a functionlocal function findenv(f)local level = 1repeatlocal name, value = debug.getupvalue(f, level)if name == '_ENV' thenreturn level, valueendlevel = level + 1until name == nilreturn nilendgetfenv = function(f)return (select(2, findenv(f)) or _G)endsetfenv = function(f, t)local level = findenv(f)if level thendebug.setupvalue(f, level, t)endreturn fendend-- 设置cls的元表setmetatable(cls,{-- 数据存储空间__data = data,-- __newindex处理赋值时的相关逻辑,类似set__newindex = function(t, key, newValue)local oldValue = data[key]-- 根据旧值的类型,判断新值的类型是否相同,不相同打印提示,相同才赋值if oldValue thenif type(oldValue) == 'function' thenprint('函数不能赋值')returnelseif type(newValue) ~= type(data[key]) thenprint('类型不匹配:', tostring(key), ' 的类型是', type(data[key]))returnendendend-- 将新值赋值data[key] = newValueend,-- __index处理获取值时的相关逻辑,类似get__index = function(t, key)if data[key] thenlocal value = data[key]--[["下面代码主要处理的是:A和B的foo函数体中都没有使用self,此时就得从全局表中获取该变量的值foo = function()print('from A', name, age)end"]]if type(value) == 'function' then-- 新建一个全局表local newG = {}setmetatable(newG, {__index = _G})-- 将数据赋值到全局表中for k, v in pairs(data) doif type(v) ~= 'function' thennewG[k] = vendend-- 设置函数的全局环境表setfenv(value, newG)end-- 返回原始值return valueendreturn nilend,-- __call可以使class创建的对象被调用,类似构造函数的用法,调用后复制出来一个实例__call = function()return clsend})return cls
endA =
class {name = '',age = 0,foo = function()print('from A', name, age)end
}B =
class {__super = A,foo = function()print('from B', name, age)end
}local a = A()
a.name = 'hanmeimei'
a.age = 17
a:foo()
local b = B()
b.name = 'lilei'
b.age = 18
b:foo()a.name = 20
a.age = '20'
b.foo = 'x'

腾讯最难lua面试题答案及解析相关推荐

  1. 数据结构题及c语言版答案9.14,十套数据结构试题+答案+难题解析(精校版)

    十套数据结构试题+答案+难题解析(精校版) 更新时间:2017/2/9 10:47:00  浏览量:643  手机版 数据结构试卷(一) 一.单选题(每题 2 分,共20分) 1. 栈和队列的共同特点 ...

  2. 高中计算机学科知识,2020下半年教师资格统考《高中信息技术学科知识与教学能力》试题答案及解析...

    2020年下半年中小学教师资格考试 <高中信息技术>参考答案及解析 [来源于网络] 一.单项选择题 1.[答案]B.中华人民共和国网络安全法. 2.[答案]C.增强现实技术. 3.[答案] ...

  3. 2019年浙江高考数学选择试题答案及解析-(word版)

    本文作者:vxbomath 老师今天给大家提供2019年浙江高考数学试题答案及解析-(word版) 并含有详细的答案解析. 推荐阅读:高中数学辅导之高考数学射影定理秒杀三角函数难题(视频) [学渣逆袭 ...

  4. android串口开发!一年后斩获腾讯T3,附面试题答案

    开头 互联网时代的到来,让我们获取知识变得更加简单,理论上讲只要你想学,便会有不尽的知识等你,只要方法得当,够努力,任何人都可以都有可能成为大牛. 自己在努力的基础上,还学习了一些高效的学习方法,让我 ...

  5. 02323_历年考试部分试题答案及解析

    文章目录 选择与填空 201810.4 进程控制块包含的信息: 标识信息(进程标识符信息), 说明信息(处理机状态信息), 现场信息(进程调度信息), 管理信息(进程控制信息) 201810.7 32 ...

  6. NOIP2009年普及组初赛试题答案及解析

    原文链接请点这: 一.单项选择题(共20题,每题1.5分,共计30分.每题有且仅有一个正确答案.) 1. 关于图灵机下面的说法哪个是正确的:( D) A.图灵机是世界上最早的电子计算机. B.由于大量 ...

  7. 阿里、百度、腾讯Java程序员面经(附带面试题答案)

    一定不要在没有面试经验的情况下先面大厂,或者是你想去的公司. 我是3月1日下午三点半在阿里的官网完善的简历,5点电话就过来了.作为一个java coder,阿里是个很好的平台,(当然C 的岗可以好好准 ...

  8. 备战金九银十,腾讯T4梳理2022年最全999道Java岗必备面试题答案

    Java集合/泛型面试题 1.ArrayLi st和1inkedList的区别 2.HashMap和HashT abl e的区别 3.Collecti on包结构,与Collections的区别 4. ...

  9. 腾讯云tcp题库包含哪些知识点?腾讯云tcp题库试题举例

    腾讯云tcp认证是腾讯公司针对于云计算.云运维.云架构等人员的高级工程师认证,为了考取腾讯tcp认证,当然需要学习腾讯云tcp题库.那么,腾讯云tcp题库包含哪些知识点?我从网上找了些腾讯云tcp题库 ...

最新文章

  1. 微信扫描二维码登入实现,网页端
  2. 认知智能再突破,阿里 18 篇论文入选 AI 顶会 KDD
  3. 智源研究院发布“智能体系架构与芯片”重大研究方向,打造通用智能处理器,突破“算法共性特征”难题...
  4. Android列表视图(List View)
  5. 系统消息发现有新的未读消息弹框提示
  6. 基于Linux的虚拟主机搭建
  7. 【CF1179 A,B,C】Valeriy and Deque / Tolik and His Uncle / Serge and Dining Room
  8. 【转】LDA数学八卦
  9. JS - Object.create(prototype)方法
  10. 浅析MSIL中间语言——基础篇
  11. MySQL学习之备份
  12. 百度进军游戏;腾讯起诉抄袭者;苹果急撤 watchOS 5.1 更新 | 极客头条
  13. OC省字典的数组摘要集
  14. BP算法和RNN_RNN/LSTM BPTT详细推导以及梯度消失问题分析
  15. p3输入p1输出c语言,单片机C语言编程基础
  16. SpringBoot(四)整合视图
  17. 如何让一个已经存在的项目跑起来
  18. Hydra 使用方法
  19. 一线开发大牛带你初步了解如何使用SpringBoot搭建框架
  20. eps倾斜摄影矢量化采集毕业设计_eps倾斜摄影矢量化dlg采集#知识参考

热门文章

  1. 每日新闻:抖音杀入小程序战场;懂车帝发布SaaS系统 ; 汉得开源其企业级PaaS平台;甲骨文推出“第二代云” 向AWS发起挑战...
  2. maven配置本地仓库、maven配置阿里中央仓库
  3. Android音视频点/直播模块开发实践总结-zz
  4. 干货 | Web前端优化及工具集锦
  5. 所生成项目的处理器架构“MSIL”与引用“ ”的处理器架构“AMD64”不匹配。
  6. MySQL基础教程---创建、查询、备份数据库
  7. 【XSY4041】搬砖(线段树)
  8. 搭建SecureCRT
  9. 数据库、MySQL基本知识
  10. implicitly has an ‘any‘ type...以及suppressImplicitAnyIndexErrors版本错误TypeScript 5.5问题