Lua:使用元表实现的一种面向对象方法调用

2024-03-25 16:48

本文主要是介绍Lua:使用元表实现的一种面向对象方法调用,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Lua:使用元表实现的一种面向对象方法调用


一、Lua中的面向对象编程

Lua中,面向对象编程主要是通过table来实现的。

Lua中,定义对象及方法:

  • 冒号定义,冒号引用
local obj = {}function obj:setname(name)self.name = name
endfunction obj:getname()return self.name
endobj:setname("test1280")
print(obj:getname())

或者:

  • 点号定义,点号引用
local obj = {}function obj.setname(self, name)self.name = name
endfunction obj.getname(self)return self.name
endobj.setname(obj, "test1280")
print(obj.getname(obj))

或者:

  • 冒号定义,点号引用
local obj = {}function obj:setname(name)self.name = name
endfunction obj:getname()return self.name
endobj.setname(obj, "test1280")
print(obj.getname(obj))

或者:

  • 点号定义,冒号引用
local obj = {}function obj.setname(self, name)self.name = name
endfunction obj.getname(self)return self.name
endobj:setname("test1280")
print(obj:getname())

使用(冒号或点号)(定义或引用),区别在于是否将对象(table)作为第一个参数传入(self、this)。

可见,冒号定义方法或引用方法,是Lua为我们实现的一种语法糖。使得我们不必显式地传入对象本身。

如果既想要通过点号引用方法,又不希望显式地将对象本身作为第一个参数传入方法,如何实现?

一种可行的方法是,通过元表实现。


二、Lua中的元表

Lua中的每个值都有一套预定义的操作集合,例如数字相加减,字符串比较,字符串连接等等。

可以通过元表来修改一个值的行为,使其在面对一个非预定义的操作时执行一个指定的操作。

Lua中的每个值都有一个元表。

table和userdata可以有各自独立的元表,其他类型的值则共享其类型所属的单一元表。

Lua在创建新table时不会创建元表。

可以通过setmetatable来设置一个值的元表;
可以通过getmetatable来获取一个值的元表;(元表是一个table)

在Lua中只能设置table的元表,在C中可以设置任何值的元表。

当访问一个table中不存在的字段时,通常会返回nil值;特别的,当这个table的元表有__index元方法时,最终返回结果是__index的返回值。

例如:

local mt = {}
mt.__index = function (t, k)return rawget(t, "_" .. k)
endlocal obj = {}
setmetatable(obj, mt) obj["_name"] = "test1280"
print(obj["name"])print(obj["xxxx"])

结果:

[test1280@node1 20190808]$ lua me.lua
test1280
nil

三、设置元表__index元方法,满足【点号引用对象方法】的需求

-- fn function name
-- fv function valuelocal mt = {}
mt.__index = function (t, k)-- obj.fn->obj._fnlocal fv = rawget(t, "_" .. k)if type(fv) ~= "function" thenreturnend-- fv  upvalue-- ... 可变形参-- 注意返回的是一个函数return function (...)return fv(t, ...) -- 强制将t注入到第一个参数end
endlocal obj = {}
setmetatable(obj, mt)function obj._setname(this, name)this.name = name
endfunction obj._getname(this)return this.name
endobj.setname("test1280")
print(obj.getname())

1.设置obj对象的元表,包含__index元方法;

2.obj.setname的过程:

obj本身没有setname的字段,因此触发__index元方法;触发元方法时,obj对象以及"setname"方法名(字符串)传入__index元方法(参数);在__index中尝试查询obj是否存在"_setname"函数;如果存在名字叫做"_setname"的方法(函数),则创建一个新的匿名函数并将其返回;obj.setname(或者obj["setname"])获取到新创建的函数;这个新创建的匿名函数的形参是...,可以接受任何变参,因为我们无法提前知悉类的每个方法的参数形式(且参数列表也不可能统一类型、数量...);然后在新匿名函数中通过upvalue的方式引用真实的方法(函数,_setname),强制注入obj对象为第一个参数;同时将形参...作为参数原封不动地传入upvalue真实的函数;

好吧,有点绕…

以上是我结合元表(__index元方法)和upvalue等原生机制实现的一种通过点号调用对象方法的方法。

虽然调用形式统一,但同时也需要付出性能降低、开销增大的代价。

有得必有失,每次创建匿名函数可能会影响到性能噢,使用时需要注意。

参考:

1.《Lua程序设计 第二版》

这篇关于Lua:使用元表实现的一种面向对象方法调用的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/845619

相关文章

Python中edge-tts实现便捷语音合成

《Python中edge-tts实现便捷语音合成》edge-tts是一个功能强大的Python库,支持多种语言和声音选项,本文主要介绍了Python中edge-tts实现便捷语音合成,具有一定的参考价... 目录安装与环境设置文本转语音查找音色更改语音参数生成音频与字幕总结edge-tts 是一个功能强大的

Java实现按字节长度截取字符串

《Java实现按字节长度截取字符串》在Java中,由于字符串可能包含多字节字符,直接按字节长度截取可能会导致乱码或截取不准确的问题,下面我们就来看看几种按字节长度截取字符串的方法吧... 目录方法一:使用String的getBytes方法方法二:指定字符编码处理方法三:更精确的字符编码处理使用示例注意事项方

pandas DataFrame keys的使用小结

《pandasDataFramekeys的使用小结》pandas.DataFrame.keys()方法返回DataFrame的列名,类似于字典的键,本文主要介绍了pandasDataFrameke... 目录Pandas2.2 DataFrameIndexing, iterationpandas.DataF

使用Python和PaddleOCR实现图文识别的代码和步骤

《使用Python和PaddleOCR实现图文识别的代码和步骤》在当今数字化时代,图文识别技术的应用越来越广泛,如文档数字化、信息提取等,PaddleOCR是百度开源的一款强大的OCR工具包,它集成了... 目录一、引言二、环境准备2.1 安装 python2.2 安装 PaddlePaddle2.3 安装

嵌入式Linux之使用设备树驱动GPIO的实现方式

《嵌入式Linux之使用设备树驱动GPIO的实现方式》:本文主要介绍嵌入式Linux之使用设备树驱动GPIO的实现方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐... 目录一、设备树配置1.1 添加 pinctrl 节点1.2 添加 LED 设备节点二、编写驱动程序2.1

Android 实现一个隐私弹窗功能

《Android实现一个隐私弹窗功能》:本文主要介绍Android实现一个隐私弹窗功能,本文通过实例代码给大家介绍的非常详细,感兴趣的朋友一起看看吧... 效果图如下:1. 设置同意、退出、点击用户协议、点击隐私协议的函数参数2. 《用户协议》、《隐私政策》设置成可点击的,且颜色要区分出来res/l

spring IOC的理解之原理和实现过程

《springIOC的理解之原理和实现过程》:本文主要介绍springIOC的理解之原理和实现过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、IoC 核心概念二、核心原理1. 容器架构2. 核心组件3. 工作流程三、关键实现机制1. Bean生命周期2.

Redis实现分布式锁全解析之从原理到实践过程

《Redis实现分布式锁全解析之从原理到实践过程》:本文主要介绍Redis实现分布式锁全解析之从原理到实践过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、背景介绍二、解决方案(一)使用 SETNX 命令(二)设置锁的过期时间(三)解决锁的误删问题(四)Re

nginx负载均衡及详细配置方法

《nginx负载均衡及详细配置方法》Nginx作为一种高效的Web服务器和反向代理服务器,广泛应用于网站的负载均衡中,:本文主要介绍nginx负载均衡及详细配置,需要的朋友可以参考下... 目录一、 nginx负载均衡策略1.1 基本负载均衡策略1.2 第三方策略1.3 策略对比二、 nginx配置2.1

Java调用Python的四种方法小结

《Java调用Python的四种方法小结》在现代开发中,结合不同编程语言的优势往往能达到事半功倍的效果,本文将详细介绍四种在Java中调用Python的方法,并推荐一种最常用且实用的方法,希望对大家有... 目录一、在Java类中直接执行python语句二、在Java中直接调用Python脚本三、使用Run