Lua创建Class

Lua 创建一个有父类的class, 实现类继承机制的场景

Lua 复制代码
--实现"把任意参数包装成表"
function cmd_PackArgs(argTab)
	if argTab == nil then
		return {};
	elseif not (type(argTab) == "table") then
		return { argTab };
	end;
	return argTab;
end;


-- 创建一个有父类的class
function cmd_CreateClass(className, super)
	local cls;
    if super then
		cls = {};
		cls.__super = super;
    else
		cls = {
			---@param argTab table 参数需要封装成table
			ctor = function(argTab) end;
		};
	end;


--给 cls 设置一个 __index 元方法,这是当访问 cls 的实例 object[k] 时,会调用的查找方法。
--self 通常表示访问的实例,k 是想访问的字段名。
	cls.__index = function(self, k)
        --rawget 是直接读取表 cls 的字段,不会触发元方法,避免死循环。这里尝试在本类 cls 中取字段 k。如果找到了,val 就不是 nil;否则是 nil。
		local val = rawget(cls, k);

        --如果本类没有找到该字段,并且存在父类 __super 才进入查找父类流程。current 从cls.__super(父类)开始。在 current(父类)中用 rawget 直接查找字段 k。如果找到(val 不再是 nil),跳出循环结束查找。如果没找到,继续向上查找父类的父类 current.__super。直到顶层父类为空或者找到成员为止
		if val == nil and cls.__super then
			local current = cls.__super;
			while current and val == nil do
				val = rawget(current, k);
				current = current.__super;
			end;
		end;
		return val;
	end;

	cls.className = function()
		return cls.__className;
	end;
	cls.__className = className;
	cls.__properties = {};	-- 属性列表

	
	---@param data any 传递的参数
	function cls:new(argTab, data)
        ---@param argTab table 参数需要封装成table
		argTab = cmd_PackArgs(argTab);
        --创建空表 o,用作实例的底层结构
		local o = {};
        --使用 cls 作为元表,设置元方法(其中包括上面你给的 __index),使实例支持类方法和继承属性访问。
		local instance = setmetatable(o, cls);
        --给实例添加 class 字段指向类本身,方便引用。
		instance.class = cls;

        --递归遍历该类及所有父类链上的 __properties 字段,将他们合并成一个总的 properties 表
		local function mergeProperties(currentCls, properties)
			if currentCls.__super then
				mergeProperties(currentCls.__super, properties);
			end;
			if currentCls.__properties then
				for k, v in pairs(currentCls.__properties) do
					if properties[k] == nil then
						properties[k] = v;
					end;
				end;
			end;
		end;

		local mergedProperties = {};
		mergeProperties(cls, mergedProperties);

        --遍历 mergedProperties,给实例 instance 赋值属性
		for k, v in pairs(mergedProperties) do
            --如果实例当前没有该属性(instance[k] == nil),才赋值,继承特性。
			if instance[k] == nil then
				if type(v) == "table" then
                    --如果属性值是 table,执行深拷贝 DeepCopyTab_New(v),防止实例之间共享同一个子表,避免副作用
					instance[k] = DeepCopyTab_New(v);
				else
					instance[k] = v;
				end;
			end;
		end;

        --假设类里有个 ctor 方法(构造函数),用来对实例进行进一步初始化。传入实例自身 instance 和两个参数 argTab、data
		instance.ctor(instance, argTab, data);
		return instance;
	end;

	return cls;
end;
相关推荐
FQNmxDG4S7 小时前
Java多线程编程:Thread与Runnable的并发控制
java·开发语言
前端老石人7 小时前
HTML 字符引用完全指南
开发语言·前端·html
matlab_xiaowang8 小时前
Redux 入门:JavaScript 可预测状态管理库
开发语言·javascript·其他·ecmascript
虹科网络安全8 小时前
艾体宝干货|数据复制详解:类型、原理与适用场景
java·开发语言·数据库
axng pmje8 小时前
Java语法进阶
java·开发语言·jvm
老前端的功夫9 小时前
【Java从入门到入土】28:Stream API:告别for循环的新时代
java·开发语言·python
qq_435287929 小时前
第9章 夸父逐日与后羿射日:死循环与进程终止?十个太阳同时值班的并行冲突
java·开发语言·git·死循环·进程终止·并行冲突·夸父逐日
止语Lab9 小时前
从手动到框架:Go DI 演进的三个拐点
开发语言·后端·golang
yaoxin5211239 小时前
397. Java 文件操作基础 - 创建常规文件与临时文件
java·开发语言·python
小短腿的代码世界9 小时前
Qt日志系统深度解析:从qDebug到企业级日志框架
开发语言·qt