Lua学习笔记_总结

目录

0.一些特性

1.变量

1.1 四种基本变量类型

1.2 变量的声明

1.3 string赋值相关

1.4 string操作相关(空着的括号如果没强调,那就是有参数)

2.运算符

2.1 算术运算符

2.2 关系运算符

2.3 逻辑运算符

2.4 其他

3.条件语句

3.1 结构一

3.2 结构二

3.3 结构三

3.4 注意事项

4.循环语句

4.1 结构一

4.2 结构二

4.3 结构三

5.复杂变量类型--函数

5.1 声明结构一

5.2 声明结构二

5.3 函数的参数(形参)

5.4 函数的返回值

5.5 重载函数

5.6 变长参数

5.7 函数嵌套

5.8 闭包

6.复杂数据类型--表

6.1 声明

6.2 赋值

6.3 遍历

6.4 模拟字典(键都是string)

6.4.1 写法

6.4.2 用法

6.4.3 一些操作

6.5 模拟类

6.5.1 成员

6.5.2 调用

6.6 一些公共操作

7.全局变量与本地变量

7.1 全局变量

7.2 本地变量

7.3 大G表

8.多脚本执行

8.1 执行

8.2 卸载

8.2.1 获取是否已经执行过

8.2.1 卸载

9.协程

9.1 创建协程

9.2 启动携程

9.3 协程挂起

10.元表与元方法

10.1 元表

10.1.1 建立元表

10.1.2 获取元表

10.2 元方法

10.2.1 __tostring

10.2.2 __call

10.2.3 运算符重载

10.2.4 __index

10.2.5 __newindex

10.3 其他一些操作

11.垃圾回收


如有错误或不妥,还请指出


0.一些特性

       (1)lua中的语句后面不需要加";",想加可以加。

       (2)lua中的索引从1开始。

       (3)lua的代码是从上到下依次执行的.

       (4)lua是解释型语言

       (5)self与this不同.


1.变量

1.1 四种基本变量类型

       (1)number:数字类型,代表整数和浮点数。

       (2)string:字符串类型,代表字符串。

       (3)boolean:布尔类型,true和false。

       (4)nil:空类型,类似c#中的null。

1.2 变量的声明

       lua中基本变量的声明不需要显式指明:

a = 1;
--type()获取类型
print(type(a));

a = true;
print(type(a));

a = "114514";
print(type(a));

--null in c#
a = nil;
print(type(a));

       运行结果:

number
boolean
string
nil

1.3 string赋值相关

       (1)string的赋值可以是单引号也可以是双引号

str1 = "双引号字符串";
str2 = '单引号字符串';

       (2)一个中文字符占三个字节,一个英文字符占一个字节;

       (3)多行打印:赋值时不用引号,用[[ 内容 ]],方括号中的换行会保留;

str4 = 
[[一
眼
顶针]]
print(str4);
print([[一
眼
顶针]]
)

       运行结果:

一
眼
顶针
一
眼
顶针

       (4)拼接使用"..",string赋值时也可以使用(boolean和nil用不了)

print("123" .. "456");
--运行结果为:123456

1.4 string操作相关(空着的括号如果没强调,那就是有参数)

       (1)#获取字符串长度;(#是通用的获取长度的关键字)

       (2)string.format():初始化,用法和c语言中的print类似;

       (3)tostring():将别的类型显式转化为字符串类型;

       (4)string.upper(str):将字符串中的小写字母变为大写;

       (5)string.lower(str):大写变小写;

       (6)string.reverse(str):字符串翻转;

       (7)string.find(str,要找的字符串):在前者中寻找后者,返回找到的字符的起点终点的索引;

       (8)string.sub(str, 截取的起始索引,终点索引):截取,不指定终点时默认到末尾;

       (9)string.rep(str, n):重复str n次;

       (10)string.gsub(str, 将要替换的字符串,用什么字符串替换):用第三参数替换str所有的第二参数;

       (11)string.byte(str, index):获取str中index位置字符的ASCII值;

       (12)string.char(str):将str从ASCII转化为字符;

print(string.format("I am %d.", 18)); --3(be similar to c)

--别的类型转字符串
b = true;
print(tostring(b)); --显式

--字符串的公共方法
str6 = "abCdEfg";
print(string.upper(str6)); --small -> big(don`t change original str if I don`t highlight)
print(string.lower(str6)); --big -> small
print(string.reverse(str6)); --reverse
print(string.find(str6, "abC")); --find with latter in the former(return first position and end position)
print(string.sub(str6, 2)); --return string between second parameter index and third parameter index(if no third paramenter -> end)
print(string.rep(str6, 1)); --repeat latter times
print(string.gsub(str6, "Cd", "??")); --replace,could return a interger(how many places changed)
local str7 = string.byte("Lua", 2); --char -> ASCII(latter is where char should be done)
print(str7);
print(string.char(str7)); --ASCII -> char

        运行结果:

I am 18.
true
ABCDEFG
abcdefg
gfEdCba
1	3
bCdEfg
abCdEfg
ab??Efg	1
117
u

2.运算符

2.1 算术运算符

       (1)加减乘取余均无变化,除法不会舍弃位数;

       (2)幂(^):a^n,a的n次方;

       (3)lua没有自增自减以及+=等复合运算符

2.2 关系运算符

       (1)大于小于,大于等于小于等于以及等于均相等;

       (2)不等于(~=)

2.3 逻辑运算符

       (1)and:类比c中的&&;

       (2)or:类比c中的||;

       (3)not:类比c中的!;

2.4 其他

       (1)不支持按位运算;

       (2)不支持三元运算;

--one: arithmetic
print("123" + 1); --The result is 124, string -> interger, then do operation
print("123.4" + 1); --The result is 124.4(god)
print("123.4" - 1);
print("123.4" * 2);
print(1 / 2); -- The result is 0.5;
print("123.4" / 2);
print("123.4" % 2); -- remainder can be a decimal
print("123.4" ^ 2);

--two: condition
--大体与c相同,除了不等于是"~="
print(1 ~= 2);

--three: logic
--"&&" equal to "and"
--"||" eaual to "or"
--"!" equal to "not"
print(true and false);
print(true or false);
print(not true);

       运行结果:

124
124.4
122.4
246.8
0.5
61.7
1.4
15227.56
true
false
true
false

3.条件语句

3.1 结构一

       if (条件) then ... end

3.2 结构二

       if (条件) then ... else ... end

3.3 结构三

       if (条件) then ... elseif ... elseif ... end

3.4 注意事项

       (1)elseif不可拆

       (2)包括条件的括号可有可无;

       (3)lua中没有switch语句;

a = 3;
--bracket can be omitted
--if...then...end
if (a == 3) then
    print("zero");

end
--if...then...else...end
if (a > 4) then
    print("one");

else
    print("two");

end
--if...then...elseif...then...elseif...then......end
if (a == 1) then
    print("three");

elseif (a == 2) then
    print("four");

elseif (a == 3) then
    print("five");

end
--no switch

--运行结果:
zero
two
five

4.循环语句

4.1 结构一

       while (条件) do ... end

4.2 结构二

       repeat ... until (结束条件)

4.3 结构三

       for i = m, n do ... end:m为初始值,n为目标值,第三参数为步长,默认为自增1;

num = 0;
--while
while (num < 5) do
    print(num);
    num = num + 1;
end

--do while(until之后的是退出条件)
repeat
    print(num);
    num = num + 1;
until (num > 8)

--for
--第三参数为步长,不填的情况下默认自增1
--第一参数初始值,第二参数目标值(到了目标值还会执行一次)
for i = 1, 5 do
    print(i);
end

print("_____________");

for i = 1, 5, 2 do
    print(i);
end

print("_____________");

for i = 5, 1 , -2 do
    print(i);
end

--运行结果:
0
1
2
3
4
5
6
7
8
1
2
3
4
5
_____________
1
3
5
_____________
5
3
1

5.复杂变量类型--函数

5.1 声明结构一

       function name() ... end

5.2 声明结构二

       name = function() ... end

5.3 函数的参数(形参)

       (1)正如声明变量不需要指明类型一样,函数的参数也不需要类型,直接写个参数名就行,就像这样:function Test(para) ... end

       (2)传递参数时根据函数功能,可惜自己决定传递什么类型的值(毕竟形参不会指明类型)

       (3)参数传递时,讲究多丢少补:如果传递的参数(实参)比函数的参数(形参)少,那么少的部分会全部补成nil,如果实参比形参多,多的部分会被丢弃

--参数类型不指定,写个名字即可
function Test3(para)
    print(para);
end

Test3(1);
Test3("test three");
Test3(true);
Test3();
--当传入参数和函数参数个数不匹配时,丢弃或者补nil
Test3(1, 2, 3);

--运行结果
1
test three
true
nil
1

5.4 函数的返回值

       (1)直接使用return返回即可

       (2)lua中的函数的返回值可以有多个,接收返回值时用多个变量接收;接收也讲究多丢少补

function Test4(a)
    return a;
end
--直接返回即可
function Test5(a)
    return a, "1919", true;
end

temp = Test4("114514");
--同时定义多个变量来接收多个返回值
temp1, temp2, temp3 = Test5(1);
print(temp);
print(temp1 .. "/" .. temp2 .. "/" .. tostring(temp3));

--运行结果
114514
1/1919/true

5.5 重载函数

       不支持捏(* ̄∇ ̄*)

5.6 变长参数

       函数形参表中写个"...",类似c#的param,通过一个表来接收

function Test6( ... )
    --接收(这是个表)
    arg = { ... };
    for i = 1, #arg do
        print(arg[i]);
    end
end

Test6(1, "801", true, 7, 8);

--运行结果
1
801
true
7
8

5.7 函数嵌套

       正如这块的标题所言,函数也是一种变量类型,所以可以作为返回值返回

function Test7()
    return function()
        print("Test7");
    end
end

Test8 = Test7();

Test8();

--运行结果
Test7

5.8 闭包

       通过调用外部函数返回的内部函数,将一个局部变量的生命周期延长,即为闭包(可能不准确)

function Test9(x)
    --通过返回一个带x值的函数,改变了x(传入参数)的生命周期,即为闭包
    return function(y)
       return x + y; 
    end
end

Test10 = Test9(10);

print(Test10(5));

--运行结果
15

6.复杂数据类型--表

6.1 声明

       对于一个变量a,用{}给他赋值(a = { }这个样子),a即为一张表

6.2 赋值

       (1)大括号里可以声明任何数据类型的变量,每个变量之间用逗号隔开;

       (2)可以用#获取表中变量的个数,但如果表中最后一个元素是nil类型,则个数减一;

       (3)可以通过数组的方式调用表中的元素;

       (4)自定义索引:见代码;

--one
--empty table
local a = {};
local b = { 1, 6, "114514", true, 5, nil };
print(#b);
--ergodic
for i = 1, #b do
    print(b[i]);
end
print("_____________");

--two(类似二维数组,但是是表)
local c = {{1, 2, "dingzhen"}, {3, 4, "yiyan"}, {"xiba"}};
--ergodic
for i = 1, #c do
    for j = 1, #c[i] do
        print(c[i][j]);
    end
end
print("_____________");

--three(自定义索引)
--自定义索引可以写零,负数乃至小数,字符串.
--遇到自定义和按顺序排的的索引重复时,以按顺序排的为准.
--#获取的长度不会包含特殊索引,如果自定义索引和按顺序排的索引中间至多差1时(自定义索引之间也是),则会补nil,长度以自定义索引为准;
--如果1和3中间差个2,那么不管后面有多少,长度都为1.
local d = {[0] = 1, [-1] = 2, 5, 6, 7, [1.2] = "woce", ["woce"] = "dingzhen", [4] = 11234, [6] = 5, abc = "abc"};
local e = {[1] = 1, [3] = 2, [4] = 4, [5] = 5};
print(d["woce"]);
print(#d);
print(#e);

--运行结果
5
1
6
114514
true
5
_____________
1
2
dingzhen
3
4
yiyan
xiba
_____________
dingzhen
6
1

6.3 遍历

       在上面我们可以知道,自定义索引写出的特殊索引不会被#计入长度,因此也无法使用循环加#的方式遍历。而在lua中,有专门为表遍历的方法:

       (1)结构一:for i, k in ipairs(table) do ... end

       (2)结构二:for i, k in pairs(table) do ... end (i和k均可以替换为别的名字)

local a = {[0] = 1, 2, 3, [-1] = 4, 5, [5] = 6};

--ipairs
--只能找到连续索引的键,且不能找到0及以下的索引
for i, k in ipairs(a) do
    print(i .. "--" .. k);
end
print("_____________");

--pairs
--找到所有
for i, j in pairs(a) do
    print(i .. "--" .. j);
end
print("_____________");
--可以只遍历键
for i in pairs(a) do
    print(i);
end

--运行结果
1--2
2--3
3--5
_____________
1--2
2--3
3--5
0--1
5--6
-1--4
_____________
1
2
3
0
5
-1

6.4 模拟字典(键都是string)

       其实就是自定义索引都写字符串(bushi)

6.4.1 写法

       (1)自定义索引写字符串

       (2)直接写个变量名字

6.4.2 用法

       (1)表后跟中括号,里面写上要调用的键的名字(a["name"])

       (2)用成员变量的方式调用(a.name)

6.4.3 一些操作

       (1)修改:调用要改的变量然后直接重新赋值

       (2)添加:通过任意一种用法直接写一个要添加的键值

       (3)删除(?):调用要删除的变量然后把它赋值为nil

--one: Implement dictionary
local a = {["name"] = "野兽先辈", ["age"] = 24, ["sex"] = "sex", ["114514"] = "1919801"};
--可用中括号访问
print(a["name"]);
--也可用类似成员变量的方式访问,但不能是数字与汉字
--print(a.114514) -> 不行
print(a.age);
--修改
a["name"] = "野兽仙贝";
print(a["name"]);
--添加, 直接新写一个
a["length"] = -1;
print(a["length"]);
--删除?
a["length"] = nil;

--ergodic
--模拟字典使用pairs
for i, v in pairs(a) do
    print(i .. "--" .. v);
end

--运行结果
野兽先辈
24
野兽仙贝
-1
age--24
name--野兽仙贝
114514--1919801
sex--sex

6.5 模拟类

6.5.1 成员

       (1)成员变量正常赋值,成员函数只能使用name = function()的形式声明

       (2)类中的变量无法像c#那样直接使用自己所属类中的变量,lua中也没有this关键字。如果想在类中使用类中的变量,可以通过表名.变量名的方式调用,或者通过self.变量名(实际上这个有时候调用的也不是所属的类)的方式调用,再或者像图中那样

       (3)self:只有在表外通过冒号声明函数时可以使用,冒号声明后会默认将调用者作为第一参数传入函数,也就是self

       (4)在类外声明类中没有的成员变量即为添加,类外的成员函数可以使用两种方式声明

6.5.2 调用

       (1)逗号调用:不会有默认参数

       (2)冒号调用:会默认将调用者作为第一参数self传进去,即便函数并没有形参

       (3)一般情况下,成员变量两种调用均可以使用,具体怎么见下

--two: Implement class
Student = 
{
    name = "henghengaaaa",
    age = 24,
    sex = true,
    Up = function()
        print("uppppppppp");
    end,

    Learn = function()
        print("good good study");
    end,

    TestParam = function(t)
        --即便是在表中调用表里的变量,也不能直接通过名字调用,可通过两种方式调用
        --1.表名.变量名(function也是一种变量)
        print(Student.name);
        --2.通过这种奇怪方法调用:把自己作为一个参数传进来,然后调用这个参数
        print(t.name);
        
    end,
}
print("_____________");
--下面两种写法效果相同
--.(点)调用方法,该是什么就是什么
Student.TestParam(Student);
--:(冒号)调用方法,会默认将调用者作为第一个参数传入方法中;
Student:TestParam();

--用冒号声明新成员函数时,默认第一个参数为调用者,可在方法中使用self关键字调用;同样,使用该方法也用冒号调用;
--也可以用点调用,但括号内要写上调用者
function Student:Score()
    self.Learn();
end
--one
Student:Score();
--two
Student.Score(Student);

print("_____________");

--在表外声明新的方法或变量,相当于添加东西
Student.work = false;
Student.Working = function()
    print("?");
end
Student.Working();
--另一种形式
function Student.Speak()
    print("Speak");
end

Student.Learn();
print(Student.name);
print("_____________");

--运行结果
_____________
henghengaaaa
henghengaaaa
henghengaaaa
henghengaaaa
good good study
good good study
_____________
?
good good study
henghengaaaa
_____________

6.6 一些公共操作

       (1)insert(T1, T2):在T1后面插入T2

       (2)sort(T, function):第二参数留空时,默认将T从小到大排序;第二参数时自定义的一个排序规则

       (3)concat(table, str):将str中的元素用字符串str串起来

       (4)remove(table, index):移除table中指定索引的元素,index留空时移除最后的索引内容


7.全局变量与本地变量

7.1 全局变量

       声明变量时不加local关键字即为全局变量,运行一次后在整个文件中都可以使用

7.2 本地变量

       声明变量时加了local关键字即为本地变量,生命周期是当前函数的作用域

--lua中的变量除了函数参数外默认是全局变量,见下
for i = 1, 2 do
    c = "woce";
end
print(c);
--要使变量为本地变量,就使用local关键字
for i = 1, 2 do
    local d = "woce";
end
print(d);
--exp:
fun = function()
    tt = "?";
end
print(tt);
fun();
--运行一次后便多了一个tt的全局变量
print(tt);

--运行结果
woce
nil
nil
?

7.3 大G表

       大G表是一个表,里面存储着所有的全局变量,名称为_G


8.多脚本执行

8.1 执行

       使用require(path)方法:括号中是文件路径,相对路径和绝对路径均可

--10_2_MultiScriptsTest
print("this is a test");

TestA = "TestA";
local testB = "testB";

return testB;
--require("脚本名"); --用于执行另外一个lua脚本,该脚本名字中不能带点
require("10_2_MultiScriptsTest"); --执行过后,可以使用其中的全局变量

print(TestA);

--运行结果
this is a test
TestA

8.2 卸载

8.2.1 获取是否已经执行过

       通过package.loaded(path)得到是否已经执行过,如果没执行过,返回nil,如果执行过,返回脚本返回值或true;

8.2.1 卸载

        将对应脚本的package.loaded(path)赋值为false或者nil(这么干是因为执行过的脚本无法重复执行)

--require加载执行后的脚本不能够再一次执行
--package.loaded[变量名]可以得到该脚本是否被执行过了
print(package.loaded["10_2_MultiScriptsTest"]);
--卸载脚本只需要让这个等于nil或者false就可以
package.loaded["10_2_MultiScriptsTest"] = nil;
--可以用一个变量接收脚本中返回的值(希望从这个脚本中获取的变量,一般情况下是一个局部变量)
local returnValue = require("10_2_MultiScriptsTest");

print(returnValue);

--运行结果
testB
this is a test
testB

9.协程

9.1 创建协程

       (1)方法一:使用coroutine.create(fun)创建,fun是一个函数,方法返回值是一个thread

       (2)方法二:使用coroutine.warp(fun)创建,返回值是一个function

9.2 启动携程

       (1)方法一:使用coroutine.resume(co),co是一个9.1方法一的协程,

       (2)方法二:直接使用9.1方法二创建的协程(实际上算是个函数了)

9.3 协程挂起

       可以在创建携程的函数中使用coroutine.yield()来挂起(暂停)协程,yield的括号里放的是返回值;可以声明变量来接收这些返回值,但变量接收的第一个返回值是协程是否启动成功(默认的);

--挂起函数执行后,相当于暂停了这个函数,里面的状态不变,再次执行时从暂停处开始
local fun2 = function()
    local i = 1;
    while true do
        print(i);
        print(coroutine.running());
        i = i + 1;
        --挂起函数(暂停), 括号内的参数是返回值
        coroutine.yield(i);
    end
end

local co3 = coroutine.create(fun2);
--通过多参数接收返回值,第一个参数是协程是否启动成功
local isOk, temp1 = coroutine.resume(co3);
print(isOk, temp1);
isOk, temp1 = coroutine.resume(co3);
print(isOk, temp1);
--另一种方式的协程,这种协程没有默认的返回值
local co4 = coroutine.wrap(fun2);
co4();
co4();
print("second返回值:" .. co4());

--运行结果
1
thread: 0000000000f303d8	false
true	2
2
thread: 0000000000f303d8	false
true	3
1
thread: 0000000000f31c18	false
2
thread: 0000000000f31c18	false
3
thread: 0000000000f31c18	false
second返回值:4

9.4 协程状态

       (1)coroutine.status(co):获取协程co的运行状态

       (2)coroutine.running():获取当前正在运行的协程,具体见下(没参数)

local statusCo3 = coroutine.status(co3);
local statusCo1 = coroutine.status(co1);
print(statusCo3);
print(statusCo1);
--running状态只能在协程中获取
--这个方法是获取当前正在运行的协程,返回一个协程号以及boolean值,boolean值判断是否是主线程
print(coroutine.running());

--运行结果
suspended
dead
thread: 00000000010460c8	true

10.元表与元方法

10.1 元表

10.1.1 建立元表

       有两个表t1和t2,使用setmetatable(t1, t2)即可将t2设置为t1的元表(第二参数为第一参数的元表),元表类似c#中的基类

10.1.2 获取元表

       getmetatable(metatable):返回一个类型和对应的号(地址?)

local meta = {};
local myTable = {};
--第一个参数为子,第二参数为父(基类)
setmetatable(myTable, meta);

--返回一个类型和专属的号(地址?)
print(getmetatable(myTable7));

--运行结果
table: 0000000000ffa730

10.2 元方法

10.2.1 __tostring

       (1)通过在元表中声明该名的函数实现

       (2)该方法会在子表被当作字符串使用时被调用

--three: specific operation--__tostring
local meta2 = {
    --这个(__tostring)会在子表被当作字符串使用时被调用
    --在里面放一个参数时,子表会默认将自己传进去;
    __tostring = function(t)
        --前提是t(子类)中有name这个属性
        return t.name;
    end,
}

local myTable2 = {
    name = "woce",
};

setmetatable(myTable2, meta2);
print(myTable2);

--运行结果
woce

10.2.2 __call

       该方法会在子表被当作函数使用时调用

--four: specific operation--__call
local meta3 = {
    __tostring = function(t)
        return t.name;
    end,
    --当子表被当作函数使用时,调用元表中的__call函数
    --第一个参数默认为自己
    __call = function(a, b)
        --打印了myTable,但由于当作字符串使用,所以调用元表的__tostring,返回了t(子表)中的元素name;
        print(a);
        --真正由用户传入的参数
        print(b);
        print("我是维新派,我只抽瑞克五.");
    end
}

local myTable3 = {
    name = "芙蓉王:";
};

setmetatable(myTable3, meta3);
--传入参数时候,传入的第一个参数是__call函数的第二个参数
myTable3(1);

--运行结果
芙蓉王:
1
抽烟我只抽瑞克五.

10.2.3 运算符重载

       在子表执行对应运算时调用:

       __add 对应 +                                                 __sub 对应 -

       __mul 对应 *                                                  __div 对应 /

       __mod 对应 %                                               __eq 对应 ==

       __lt 对应 <                                                      __le 对应 <=

       __concat 对应 ..

--five: specific operation --operator overloading(运算符重载)
local meta4 = {
    --+
    __add = function(a, b)
        --前提是有对应元素
        return a.age + b.age;
    end,
    ---
    __sub = function(a, b)
        return a.age - b.age;
    end,
    --*
    __mul = function(a, b)
        return a.age * b.age;
    end,
    --/
    __div = function(a, b)
        return a.age / b.age;
    end,
    --%
    __mod = function(a, b)
        return a.age % b.age;
    end,

    --==
    __eq = function(a, b)
        return true;
    end,
    --<
    __lt = function(a, b)
        return false;
    end,
    --<=
    __le = function(a, b)
        return false;
    end,
    --..
    __concat = function(a, b)
        return "123456789";
    end,

}
local meta5 = {
    __add = function(a, b)
        return 3 * (a.age + b.age);
    end
}

local myTable4 = {
    age = 1;
};

local myTable5 = {
    age = 2;
}
setmetatable(myTable4, meta4);
setmetatable(myTable5, meta5);

--一个有重载一个没重载,优先以有重载为准,不论先后
--两个都有重载,以前面那个表的重载为准
print(myTable4 + myTable5);
print(myTable5 + myTable4);

print(myTable4 - myTable5);
print(myTable4 * myTable5);
print(myTable4 / myTable5);

print(myTable5 == myTable4);
print(myTable4 < myTable5);
print(myTable4 <= myTable5);
print(myTable4 .. myTable5);

--运行结果
3
9
-1
2
0.5
true
false
false
123456789

10.2.4 __index

       调用子表元素找不到时,就会从对应元表中__index所指的表中寻找该元素;

--__index
local meta6Father = {
    name = "xuebao";
}
meta6Father.__index = meta6Father;
local meta6 = {
    age = 5;
    --不能用下面形式写
    --__index = meta6 --因为meta6还没被声明完,这个时候将他赋给别的变量只会是nil
}
meta6.__index = meta6;

local myTable6 = {};
setmetatable(meta6, meta6Father);
setmetatable(myTable6, meta6);
--在子表中找不对这个元素时,就会在元表中__index所指向的表中寻找该元素.
print(myTable6.age);
--套娃
print(myTable6.name);

--运行结果
5
xuebao

10.2.5 __newindex

       为子表中元素赋值时,如果没有找到该元素,就会从对应元表中__newindex所值的表中寻找该元素并赋值;

--__newindex(类比上面那个__index)
local meta7 = {
    --把这个name去掉后,下面第一个打印会是nil,第二个会在对应位置新建个指定元素并赋值
    name = "123";
}
local myTable7 = {}
meta7.__newindex = meta7;
meta7.__index = meta7;

setmetatable(myTable7, meta7);
print(myTable7.name);
--对子表元素赋值时,如果子表中没有该元素,就会在其元表中__newindex所指的表中寻找该元素并对其赋值
myTable7.name = "456";
print(myTable7.name);

--运行结果
123
456

10.3 其他一些操作

       (1)rawget(table, name):在不涉及元表的情况下,仅在table中调用name变量;

       (2)rawset(table, name, value):在不涉及元表的情况下,仅在table中为name赋值,值为value;

--myTable7见上
--rawget(不会涉及元表,只会在自己里面找)
print(rawget(myTable7, "name"));
--rawset(同上),返回值是一张表,找不到的话会直接加一个
print(rawset(myTable7, "name", "???"));
print(myTable7.name);

--
nil
table: 00000000013138a0
???

11.垃圾回收

       (1)collectgarbage("count"):以K(kb)为单位返回Lua使用的总占用,乘以1024便是字节数

local test1 = { 1, 2, 3};

print(collectgarbage("count"));

--运行结果
21.400390625

       (2)collectgarbage("collect”):做一次垃圾回收,虽然lua有自动垃圾回收,但建议手动

local test1 = { 1, 2, 3};

print(collectgarbage("count"));

collectgarbage("collect");

print(collectgarbage("count"));

--运行结果
21.4091796875
21.1669921875

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值