lua 打印对table中的字符赋值时的堆栈日志

今天日常码代码时遇到一个问题,对一个表的字段赋值时,后期使用时 不知何时,又在哪里改变了这个table中的字段的值,代码又很多,一行一行找很麻烦,我们可以使用 lua 中的元方法实现 当给table中的一个字段赋值时 我们就打印赋值堆栈日志 我们首先要了解 元方法 __index 和 __newindex

1. __index

lua中的元方法 __index 有 A ,B两个表, B是A的元表 , 当调用 A.a 的时候访问了A中不存在的字段 ,如果有元表,会调用 元表(B)中的__index 如果元表中没有 __index 方法,返回 nil 如例1

--例 1
	A = {
		
	}
	B = {
		a = 1
	}
	--设置元表
	setmetatable(A, B)

lua运行时栈和堆怎么分配 lua 打印堆栈_开发语言

例2实现实现了预期的效果

--例 2
	A = {
		
	}
	B = {
		a = 1
	}
	B.__index = B
	--设置元表
	setmetatable(A, B)

lua运行时栈和堆怎么分配 lua 打印堆栈_lua_02


__index 是一个表的时候 ,会去表中找到访问的字段。 当__index 是一个函数时会调用这个函数。

A = {
		
	}
	B = {
		a = 1
	}
	B.__index = function(t, k)
		print("调用了__index元方法")
	end
	--设置元表
	setmetatable(A, B)

lua运行时栈和堆怎么分配 lua 打印堆栈_lua_03


虽然调用了__index 但是还是返回了 nil, 在元方法中 return 需要的值即可

B.__index = function(t, k) 
	print("调用了__index元方法")
	return 1
end

lua运行时栈和堆怎么分配 lua 打印堆栈_开发语言_04

2. __newindex

lua中的__newindex 元方法 跟 __index 元方法类型 __index 是访问一个不存在的字段时调用 __newindex 是对表中不存在的字段赋值时调用 __newindex 用于对表中不存在的字符赋值,赋值,赋值,__index 是访问, 访问, 访问
__newindex 是一个表时 对这个表赋值

A = {
		
	}
	B = {
	
	}
	B.__newindex = B
	--设置元表
	setmetatable(A, B)
	A.name = "B"
	print(A.name)
	print(B.name)

lua运行时栈和堆怎么分配 lua 打印堆栈_赋值_05


这就是所谓的隔山打牛

当 __newindex 是一个方法时

A = {
		
	}
	B = {
	
	}
	B.__newindex = function(t, k, v)
		print("调用了 __newindex 元方法")
	end
	--设置元表
	setmetatable(A, B)
	A.name = "B"
	print(A.name)
	print(B.name)

lua运行时栈和堆怎么分配 lua 打印堆栈_lua_06


如果要设置值的话 不用 直接 t[k] = v (t 的元表中不能有 __newindex 元方法) 这样会进入死循环 ,使用 rawset(t, k, v) 忽略 __newindex引用

A = {
		tag = "a"
	}
	B = {
		tag = "b"
	}
	B.__newindex = function(t, k, v)
		print("调用了 __newindex 元方法")
		print(t.tag)
		rawset(t,k,v)
	end
	--设置元表
	setmetatable(A, B)
	A.name = "B"
	print(A.name)
	print(B.name)

lua运行时栈和堆怎么分配 lua 打印堆栈_unity3d_07

3.我们了解了 __index 和 __newindex 来实现我们的对表赋值时, 就打印日志是从何处赋值

local assignment = function(monitor)
		-- monitor 需要监控的表
		if	monitor == nil or type(monitor) ~= "table" then 
			return
		end
		-- 赋值,访问 数据都存入cacheTable表,
		-- 这样的话 monitor表,一直是没有任何字段的,每次访问、赋值都会执行元方法 __index、__newindex
		local cacheTable = {}
		local _index = function(t, k)	
			return cacheTable[k]
		end
		local _newindex = function(t,k,v)
			print("字段名赋值 = " .. k, debug.traceback())
        	rawset(cacheTable, k, v)
		end
		setmetatable(monitor, {__index = _index, __newindex = _newindex})
	end
	A = {}
	assignment(A)
	A.name = "张三"
	A.sex = "男"
	A.age = "26"
	print(A.name)
	print(A.sex)
	print(A.age)

lua运行时栈和堆怎么分配 lua 打印堆栈_lua运行时栈和堆怎么分配_08