当前位置:网站首页>Interaction between C language and Lua (practice 3)
Interaction between C language and Lua (practice 3)
2022-06-22 04:19:00 【ufgnix0802】
C Language and Lua Interaction ( Practice three )
C Language to create metatable( Metatable )
metatable( Metatable )
This section goes to the rookie tutorial -Lua Metatable (Metatable).
stay Lua table We can access the corresponding key To get value value , But it's not possible for two table To operate ( For example, add together. ).
therefore Lua Provides a meta table (Metatable), Allow us to change table act , Each behavior is associated with a corresponding meta method .
for example , Using a meta table, we can define Lua How to calculate two table The addition operation of a+b.
When Lua When trying to add two tables , First check whether one of the two is called __add Field of , If you find , Then call the corresponding value .__add And so on , Its corresponding value ( It is often a function or table) Namely “ Metamethod ”.
There are two important functions to deal with meta tables :
setmetatable(table,metatable): For the specified table Set meta table (metatable), If meta table (metatable) in __metatble Key value ,setmetatable Will fail .
**__metatable This key can protect the meta table , If this key appears in the meta table, the meta table cannot be modified .** as follows :
test = { } b = { __metatable = "dlw"} setmetatable(test,b) getmetatable(test) setmetatable(test,{ __index = { foo = 3}})

because b In the meta table __metatble key , When we compare it with test When a table is associated , We go through getatable It was found that... Could not be accessed b The address of the meta table , But only access to __metatble The corresponding value , And after that, we are right test When modifying the meta table in the table ( call setmetatable) It was a failure. . explain __metatble Key pairs protect the meta table . Once set up , The meta table cannot be modified again .
- getmetatable(table): Returns the meta table of the object (metatable).
The following example demonstrates how to set a meta table for a specified table :
mytable = {
} -- Common watch
mymetatable = {
} -- Metatable
setmetatable(mytable,mymetatable) -- hold mymetatable Set to mytable The yuan table of
The above code can also be directly written as the following code :
mytable = setmetatable({
},{
})
The following is the return object element :
getmetatable(mytable) -- This will return to mymetatable The address of
__index Metamethod
This is a metatable The most commonly used keys .
When you access it with a key table When , If this key has no value , that Lua Will look for the table Of metatable( Suppose there is metatable) Medium __index key . If __index Contains a table ,Lua Will look up the corresponding key in the table .
other = {
foo = 3}
t.foo
t.bar
getmetatable(t).__index.foo
The operation results are as follows :

If __index If you include a function ,Lua That function will be called ,table And keys are passed as arguments to the function .
__index Meta method to see if the elements in the table exist , If it doesn't exist , The return result is nil; If it exists, it is determined by __index Return results .
-- main.lua
mytable = setmetatable({
key1 = "value1"},{
__index = function(mytable,key) -- The first parameter is the table , The second parameter is found key
if key == "key2" then
return "metatablevalue"
else
return nil
end
end
})
print(mytable.key1,mytable.key2)
The operation results are as follows :

Instance analysis :
- mytable The table is assigned as {key1 = “value1”}
- mytable Set up a meta table , Meta methods have __index.
- stay mytable Find in table key1, If you find , Return the element , If you can't find it, continue .
- stay mytable Find in table key2, If you find , return metatablevalue, If you can't find it, continue .
- Judge whether the meta table has __index Method , If __index Method is a function , The function is called .
- Meta method to see if “key2” Key parameters (mytable.key2 Have been set ), If you pass in “key2” Parameter return “metatablevalue”, Otherwise return to mytable Corresponding key value .
We can simply write the above code as :
mytable = setmetatable({
key1 = "value1"}, {
__index = {
key2 = "metatablevalue" } })
print(mytable.key1,mytable.key2)
summary
Lua Rules for finding a table element , In fact, there are three steps as follows :
- Find in this table , If you find , Return the element , If you can't find it, continue .
- Judge whether the table has meta table , If not, return nil, Otherwise continue .
- Judge whether the meta table has __index Method , If __index Method is nil, Then return to nil; If __index The method is a table , Then repeat 1、2、3; If __index Method is a function , Returns the return value of the function .
__newindex Metamethod
__newindex Meta methods are used to update tables ,__index Is used to access the table .
When you assign a value to a missing index of a table , The interpreter will look up __newindex Metamethod ; If it does exist, it will call this function without assignment .
The following example demonstrates __newindex Application of element method :
-- main.lua
mymetatable = {
}
mytable = setmetatable({
key1 = "value1"},{
__newindex = mymetatable})
print(mytable.key1)
mytable.newkey = " The new value 2"
print(mytable.newkey,mymetatable.newkey)
mytable.key1 = " The new value 1"
print(mytable.key1,mymetatable.key1)

Of course , If the table is not associated with a meta table ( That is, it is just an ordinary table ), Will directly add key values to the table . as follows :
-- main.lua
mytable = {
key1 = "value1"}
print(mytable.key1)
mytable.key2 = " The new value 2"
print(mytable.key2)
print(getmetatable(mytable))

In the above example, the meta method is set in the table __newindex, On the new index value (newkey) assignment (mytable.newkey = “ The new value 2”), Will call metamethods , Without assignment . And if the key index value already exists (key1), Then the assignment will be made , Instead of calling metamethods __newindex.
The following example uses rawset Function to update the table :
rawset(table,index,value)
Without triggering any meta methods, the table[index] Set to value.table It must be a table ,index It can be nil And NaN Any value other than .value It could be anything Lua value .
-- main.lua
mytable = setmetatable({
key1 = "value1"},{
__newindex = function(mytable,key,value)
rawset(mytable,key,"\"" .. value .. "\"")
end
})
mytable.key1 = "new value"
mytable.key2 = 4
print(mytable.key1,mytable.key2)
The operation results are as follows :

Add an operator to the table
The following example demonstrates the addition of two tables :
-- Calculate the maximum value in the table ,table.maxn stay Lua5.2 ... is no longer available in the above version
-- The maximum key value function in the user-defined calculation table table_maxn, That is, calculate the number of elements in the table
-- main.lua
function table_maxn(t)
local mn = 0
for k,v in pairs(t) do
if mn < k then
mn = k
end
end
return mn
end
-- Add two tables
mytable = setmetatable({
1,2,3},{
__add = function(mytable,newtable)
for i = 1,table_maxn(newtable) do
table.insert(mytable,table_maxn(mytable)+1,newtable[i])-- Go to mytable Add a new key value to the
end
return mytable
end
})
secondtable = {
4,5,6}
mytable = mytable + secondtable
for k,v in pairs(mytable) do
print(k,v)
end
The operation results are as follows :

__add The key is contained in the meta table , And add . The corresponding operation list in the table is as follows :( Be careful :__ Are two underscores )
| Pattern | describe |
|---|---|
| __add | The corresponding operator ‘+’. |
| __sub | The corresponding operator ‘-’. |
| __mul | The corresponding operator ‘*’. |
| __div | The corresponding operator ‘/’. |
| __mod | The corresponding operator ‘%’. |
| __unm | The corresponding operator ‘-’. |
| __concat | The corresponding operator ‘…’. |
| __eq | The corresponding operator ‘==’. |
| __lt | The corresponding operator ‘<’. |
| __le | The corresponding operator ‘<=’. |
__call Metamethod
__call Meta methods in Lua When a value is called . The following example demonstrates how to calculate the sum of elements in a table :
-- Calculate the maximum value in the table ,table.maxn stay Lua5.2 ... is no longer available in the above version
-- The maximum key value function in the user-defined calculation table table_maxn, That is, calculate the number of elements in the table
function table_maxn(t)
local mn = 0
for k, v in pairs(t) do
if mn < k then
mn = k
end
end
return mn
end
-- Definition meta method __call
mytable = setmetatable({
10},{
__call = function(mytable,newtable)
sum = 0 -- The sum of the data of the two tables
for i = 1,table_maxn(mytable) do
sum = sum + mytable[i]
end
for i = 1,table_maxn(newtable) do
sum = sum + newtable[i]
end
return sum
end
})
newtable = {
10,20,30}
print(mytable(newtable))
The operation results are as follows :

__tostring Metamethod
__tostring Meta methods are used to modify the output behavior of the table , That is, the table is called when it is output . In the following example, we customize the output of the table :
-- main.lua
mytable = setmetatable({
10,20,30},{
__tostring = function(mytable)
sum = 0
for k,v in pairs(mytable) do
sum = sum + v
end
return ' The sum of all elements in the table is ' .. sum
end
})
print(mytable)
The operation results are as follows :

Lua object-oriented
Reference link :https://zhuanlan.zhihu.com/p/421575005
Lua There is no object-oriented concept in itself , however table The various uses of the can simulate similar object-oriented operations .Lua The only data structure in is Table, It's a natural , A class is naturally a Table.
Person = {
age = 10,
name = "ee",
Init = function(age,name)
Person.age = age;
Person.name = name;
end
}
print(Person.age,Person.name) --10 "ee"
Person.Init(1," object-oriented ")
print(Person.age,Person.name) -- 1 " object-oriented "
Above ,Person It's a simple Table, It can also be regarded as a basic class , Have age、name Two fields ( attribute ),Init Method . Directly to Person Calling methods and fields in the table at the beginning .
Of course , This is just a simple class simulation , There can only be one , And cannot be Person As a template , Create multiple Person example . And that's where it comes in Lua The yuan table of (metatable) Trace method (metaMethod).
Metatable and metamethod
The function of meta table is to use a table as a template , Make it possible to clone multiple instances of an object . Meta table can enable the tables generated by associating with the meta table to share the methods and attributes of the meta table . The function of meta method is to make Table The operation between tables becomes more free and customized . The above Person Make changes as follows :
-- main.lua
Person = {
age = 10,
name = "ee",
Init = function(age,name)
Person.age = age;
Person.name = name;
end
}
print(Person.age,Person.name) --10 ee
Person.Init(1," object-oriented ")
print(Person.age,Person.name) --1 object-oriented
--self And “:” Symbols usually appear at the same time ,“:” The symbol is equivalent to the default Person Pass in , And operations within functions :self = &Person,&Person stay C/C++ Is similar to taking Person The address of
function Person:New(age,name)
local o = {
} --local Explicitly indicate that the variable is a local variable
setmetatable(o,self) --self Be similar to C++ Medium this The pointer , Point to the overall situation Person
self.__index = self -- because o This table is related to Person This meta table , however Person Meta table does not define __index, That is, you cannot access Person Properties and methods of , So how to make o Tables can access Person Properties and methods in ? utilize __index Characteristics of , We explicitly define Person Metatable __index Point to itself , Then it means that Person The properties and methods of are exposed directly , such o Tables can access Person All attributes and methods in the meta table .
o.age = age --o.age Medium age It's actually Person Medium age
o.name = name --o.name Medium age It's actually Person Medium name
return o -- Put the new instance object back
end
function Person:Print()
print(self.age,self.name)
end
local p = Person:New(2,"tt3")
p:Print() --2 "tt3"
local p2 = Person:New(3,"ttt")
p:Print() --2 "tt3"
p2:Print() --3 "ttt"
print(getmetatable(p),Person) -- table: 00000242651761E0 table: 00000242651761E0
print(getmetatable(p2),Person) -- table: 00000242651761E0 table: 00000242651761E0
setmetatable(t,mt) Indicates that a table t The meta table Association of is mt, So every call New After method , The returned tables are all associated with the same meta table , That's not enough , The returned table is already associated with the meta table Person, But it is only related , A new generation of p、p2 Still can't call Person Properties and methods in , Because this is the operation between tables .
At this point, you need to use the original method .__index Meta methods define the relationship between meta tables and associated tables : If you can find the called method and field in the association table , Call... In the associated table , If the method and field cannot be found in the associated table , Then go back to the meta table to find the corresponding method and field , If so, call . If not, it will prompt that the method and field do not exist .
such , When calling p:Print() Follow p2:Print() When ,p Follow p2 In fact, there is no Print() Method , But the output is correct , It is the one that calls the meta table Print() Method . This correctly simulates the process of generating instances of objects .
Class inheritance
One of the characteristics of object-oriented is inheritance ,Lua The element root method can also simulate ,Teacher Inherited to Person, Rewrite the Print() Method .
-- main.lua
Person = {
}
function Person:New(age,name)
local o = {
}
setmetatable(o,self)
self.__index = self
o.age = age
o.name = name
return o
end
function Person:GetAge()
return self.age
end
function Person:Print()
print(self.age,self.name)
end
Teacher = Person:New() -- Don't pass it on , The default input is nil nil, here Teacher = {age = nil,name = nil}, Its associated meta table Person = {__index = Person,GetAge,Print}
function Teacher:New(age,name,course)
local t = {
}
self.age = age
self.name = name
setmetatable(t,self)
self.__index = self
t.course = course -- t = {course = course,Print}, Its association table is Teacher = {__index = Teacher,age = age,name = name}, The association table of the association table is Person = {__index = Person,GetAge,Print}
return t
end
function Teacher:Print()
print(self.age,self.name,self.course)
end
local t1 = Teacher:New(33," Teacher wang "," Chinese language and literature ")
t1:Print() -- 33 Teacher wang Chinese language and literature
print("age",t1:GetAge()) -- age 33
Teacher I didn't rewrite it GetAge() Method , then t1:GetAge() But the correct output , It can be seen that this method is inherited correctly , And redefine Print() Method , It is also a normal output , It can be seen that it is correct .
C Language use metatable( Metatable )
How to build the environment can be referred to :https://blog.csdn.net/qq135595696/article/details/125137333?spm=1001.2014.3001.5501
stay lua.c Medium main Function , Delete existing code , Change to the following code :
#define LUA_TEST "LUA_TEST"
struct tagTest
{
int a;
};
static int f_gc(lua_State* L)
{
struct tagTest* p = (struct tagTest*)luaL_checkudata(L, 1, LUA_TEST);// Test whether it belongs to the meta table Failure to return NULL, First press in the custom array , At the bottom of the stack
printf(" call gc Destroyed the object ");
return 0;
}
static int f_tostring(lua_State* L)
{
struct tagTest* p = (struct tagTest*)luaL_checkudata(L, 1, LUA_TEST);// Test whether it belongs to the meta table Failure to return NULL, First press in the custom array , At the bottom of the stack
lua_pushstring(L, "f_tostring LUA_TEST");
return 1;// The return value represents the pressed parameters
}
static int f_GetA(lua_State* L)
{
struct tagTest* p = (struct tagTest*)luaL_checkudata(L, 1, LUA_TEST);// Test whether it belongs to the meta table Failure to return NULL, First press in the custom array , At the bottom of the stack
lua_pushinteger(L, p->a);
return 1;// The return value represents the pressed parameters
}
static int f_SetA(lua_State* L)
{
//printf("%d\n", lua_gettop(L));
int top = lua_gettop(L);
struct tagTest* p = (struct tagTest*)luaL_checkudata(L, 1, LUA_TEST);// Test whether it belongs to the meta table Failure to return NULL, First press in the custom array , At the bottom of the stack
int a = luaL_checkinteger(L, 2);// Data is the last element at the bottom of the stack
p->a = a;
return 0;// The return value represents the pressed parameters
}
/* ** Meta table processing method */
static const luaL_Reg flib[] = {
{
"SetA",f_SetA},
{
"GetA",f_GetA},
{
"__gc", f_gc},// Call... When deleting
{
"__tostring", f_tostring},
{
NULL, NULL}
};
// Create a meta table
static void createMeta(lua_State* L)
{
luaL_newmetatable(L, LUA_TEST);// Create a meta table
lua_pushvalue(L, -1);// take -1( To the top of the stack ) Make a copy of the element of position and put it back on the stack
lua_setfield(L, -2, "__index");// It is similar to metatable.__index = metatable The operation of , This action will pop up -1( To the top of the stack ) Location elements
luaL_setfuncs(L, flib, 0); /* Add method to meta table */
lua_pop(L, 1); /* eject newmetabhle The yuan table of */
}
static int createTest(lua_State* L)
{
// Create a user data lua The interior will automatically release
struct tagTest* p = (struct tagTest*)lua_newuserdata(L, sizeof(struct tagTest));
luaL_setmetatable(L, LUA_TEST);// And meta table
return 1;
}
int main(int argc, char** argv) {
// Create a virtual machine
lua_State* L = luaL_newstate();
// Load some common system libraries
luaL_openlibs(L);
createMeta(L);// Create a meta table
lua_pushcfunction(L, createTest);// Push in a function
lua_setglobal(L, "createTest");// Name the function “createTest”
if (luaL_dofile(L, "main.lua"))
printf("%s\n", lua_tostring(L, -1));
// Shut down the virtual machine
lua_close(L);
return 0;
}
among ,main.lua The code for is as follows ( Pay attention to the need to follow lua.c Files are placed in the same file path ):
-- main.lua
local test = createTest()
test:SetA(10)
print(test:GetA())
print(test)
The operation results are as follows :

边栏推荐
- Idea blue screen solution
- With this set of templates, it is easier to play with weekly, monthly and annual reports
- CAPL学习之路-以太网函数
- Existing requirements synchronize other database user information to our system. Their primary key ID is string and our primary key is long
- Handling of noready fault in kubernetes cluster
- Wechat applet uploading seven cattle cloud laravel
- 积加ERP全局参数灵活配置成本取值规则,核算全面到位
- Laravel realizes file (picture) uploading
- Bubble sort
- Window common shortcut keys
猜你喜欢
随机推荐
A solution to the conflict between the keywords of DM data and the fields of the table
Go learning notes
La première femme vient à 3A? Est - ce que Bright name, approuvé par IGN, peut mettre en évidence le classement
哈夫曼树
IDEA安装及其使用详解教程
Windows10 cannot access LAN shared folder
树莓派初步使用
SQL operation: with expression and its application
Wechat applet uploading seven cattle cloud laravel
每日一问:ArrayList和LinkedList的区别
Spark - executor initialization &
【写文章神器】标记语言Markdown的使用
Is it safe to open an account in Guoyuan futures?
Some journals of C51
What is the value of the FC2 new domain name? How to resolve to a website?
Popular science of source code encryption technology
yum命令
kubernetes集群中工作节点Noready故障处理
Clue binary tree
Laravel realizes file (picture) uploading









