自己的Lua学习历程

Lua学习

  1. 注释代码:
--[[
print(10)
--]]
  1. 重新启用已注释的代码:
    在第一行行首多添加一个"-"
---[[
print(10)
--]]
  1. Lua默认将一个没有声明的变量视为全局变量
    如果想删除一个全局变量,只需要将其赋值为nil

  2. type(X) 返回的值永远是string,无论X取值如何,因为type函数总是返回字符串

  3. Lua语言中整数没有类型,用number泛指数字类型

  4. 修改部分字符串函数

gsub(a,"1","2")

意思是将a字符串中的1改为2

  1. Lua中声明一个字符串可以用" "也可以用’ ’
a="line"
b='line'
  1. /加最多3个十进制数字表示以ASCII码为索引的字符


a/97 所表示的内容一致

  1. 可以在两个方括号之间加入任意个等号作为呼应

    [=[
    ]
    =]
    为一组字符串

  2. 两个字符串连接用. .(注意前加空格),在Lua中,字符串是不可改变的值,连接字符串只会创建一个新的字符串

print(10 ..20)

输出为1020

  1. tonumber()将一个字符串转换成数字(显式转换)
a={}
i=10 j=11
a[j]="abc"
print(a[tonumber(i)+1])

输出结果为abc

  1. 在字符串前加#来获得字符串长度
print(#a)
  1. table没有固定的大小,动态分配内存
a={}

创建了一个table
注意:在Lua中,索引值通常习惯用1开始,并不是0
但可以手动设置table索引为0(不推荐)

a={[0]="zero","one"}

这样zero的索引就是0,one的索引就是1了
但不推荐!!!

  1. for循环
for i=1,1000 do a[i]=1*2 end

表示数组a中1-1000每个元素做i*2运算

  1. 如果table索引为空,则会返回nil

  2. 可以用语法糖 a.x来索引table,a.x表示用字符串x来索引table,也可以用运算符来作为索引符,但需要显式表达["+"]

a={["+"]=10}
x="y"
a[x]=10
s="+"
print(a[x])
print(a.y)
print(a[s])

返回值都为10

  1. 长度操作符#用于返回一个数组或线性表中最后一个索引值
for i=1,#a do
print(a[i])
end

输出所有行

a[#a]=nil

删除最后一个值

a[#a+1]=v

将v添加至列表末尾

  1. 当数组中包含空隙时,Lua默认该数组以空隙位置结束.如果要返回该数组的最大正索引数,应使用table.manx(a)

  2. x%1的结果是x的小数部分,x%0.1的结果是x精确到小数点后两位的结果,x#0.01是x精确到小数点后两位的结果

x=math.pi
print(x%1)

结果为0.14159265358979

x=math.pi
print(x%0.01)

结果为0.001592653589793

  1. 在Lua中,~=相当于!=

  2. 在Lua中,只能对两个数字或两个字符串做大小性比较,而数字和字符串之外的其他类型只能进行相等性或不等性比较

  3. 2<15是true,但"2"<"15"是false,因为是按照字母次序来比较的

  4. 在Lua中,对于and操作符来说,如果第一个操作数为假,则返回第一个操作数,否则返回第二个操作数.对于or操作符来说,如果第一个操作数为真,则返回第一个操作数,否则返回第二个操作数

  5. andor和C语言中的||,&&一样,都是用"短路求值",也就是说,只会在需要的时候才回去评估第二个操作数,如果第一个为真,则不判断第二个操作数.

if not x then x=v end

上保险
表示如果x为假时,将x设为v.

max=(x>y) and x or y

等价于C语言中的(前提是x不为false)

max=(x>y)?x:y
a={x=0,"r"}

等价于

a={["x"]=0,[2]="r"}
  1. table中分号视为逗号,用于分割不同类的字符
a={x=10;"one"}
  1. Lua允许多重赋值
a,b=10,20

则a等于10,b等于20

x,y=y,x

表示x与y互换

  1. Lua总是会将等号右边值的个数调整到与左边个数相等,如果不够则多余的变量赋值为nil,如果超出,则删除超出部分.
a,b,c=0
print(a,b,c)

结果为 0 nil nil

  1. 在Lua中,用local声明局部变量,在开发中尽可能的多使用局部变量是一种好习惯

local foo=foo

这句代码创建了一个foo,并用全局变量的值初始化它
这句代码的作用是,如果后续操作改变了全局变量foo,那么这里的局部变量就保存了它本来的值

  1. if,for,whileend为终止符,repeatuntil为终止符

  2. if then else语句

if a<b then return a else return b end 

如果a小于b取a,否则取b

  1. 在Lua中,不支持switch语句

  2. 在Lua中,for有两种形式:数字型和泛型,38-41讲的是数字型

for i=exp1,exp2,exp3 do <执行体> end

表示i从exp1变化到exp2,每次变化都以exp3为步长,这里exp3可以写,如果不写默认为1

for i=10,1,-1 do print(i) end

输出结果为 10,9,8,7,6,5,4,3,2,1

  1. 如果不想给循环次数设置上限的话,可以使用常量 math.huge
for i=1,math.huge do <执行体> end
  1. for循环中的三个表达式都是在循环开始时一次性求值的
for i=1,f(x) do print(i) end

这里f(x)只会运算一次

  1. for循环中,控制变量都会被自动转化为局部变量,因此在end之后就不存在了
for i=1,10 do print(i) end
print(i)

输出为1,2,3,4,5,6,7,8,9,10,nil

  1. Lua的基础库提供了ipairs,是用于遍历数组的迭代器函数
for i,v in ipairs(a) do print(v) end

打印数组a的所有值

for k in pairs(t) do print(k) end

注意这里是pairs,迭代table元素用pairs
打印table t 中的所有key

  1. 标准库提供了几种迭代器:迭代文件中每行的(io.lines),迭代table元素的(pairs),迭代数组元素的(ipairs),迭代字符串中单词的(string,gmatch)等等
  2. 泛型for和数字型for一样,for中的循环变量也是局部变量
  3. 在Lua中,breakreturn只能是一个块的最后一条语句
o.foo(0.x)

等价于

o:foo(x)

这里的冒号操作符使调用o.foo的同时将o隐含地作为函数的第一个参数

  1. 函数的实参与形参数量也遵循多重赋值原则,参考31
  2. Lua中的函数允许返回多个结果
s,e=string.find("hello Lua users","Lua")
print(s,e)

查找字符串函数
返回值为 7 9

  1. 如果一个函数调用不是一系列表达式的最后一个元素,那么只会产生一个值

假设有以下定义

function foo2() return "a","b" end
x,y=foo2(),20

这里输出x=“a”,y=20

50.当函数出现在一个表达式中,Lua会将其返回值数量调整为1

假设有以下定义

function foo2() return "a","b" end
print(foo2(),1)

输出为a 1

  1. table构造式可以完整地接受一个函数调用的所有结果

假设有以下定义

function foo2() return "a","b" end
t={foo2()}

在这里t={“a”,“b”}

注意: 这种行为只有当一个函数调用作为最后一个元素时才会发生,而在其他位置上的函数调用总是只产生一个结果值

t={foo0(),foo2()}

在这里 t[1]=nil,t[2]=“a”

  1. return 语句可以返回函数f的所有返回值
  2. 也可以将一个函数放入一堆圆括号中,从而迫使它只返回一个结果
print((foo2()))

这里输出 a

  1. unpack函数.它接受一个数组作为参数,并从下标1开始返回该数组的所有元素
print(unpack{10,20,30})

输出 10 20 30

  1. … (变长参数) 表示该函数可接受不同数量的实参
function add(...)
local s=0
for i,v in ipairs{...} do
 s=s+v
end
return s
end
print(add(3,4,12,13,12))

输出为44

function foo(a,b,c)

等同于

function foo(..)
local a,b,c=...
end
  1. 遍历变长参数只需要使用表达式{…},但无法遍历包含nil的变长参数.调用select时,必须传入一个固定参数selector,如果selector为数字n,那么select返回它的第n个可变实参,否则,selector只能为字符串#,这样会返回变长参数的总数.
for i=1,select('#', ...) do
local arg=select(i, ...)
<循环体>
end

这样会得到第i个参数
select会返回所以变长参数的总数,其中包括nil

  1. 在Lua中,函数是一种"第一类值",也就是说可以把一个函数存储到一个变量中,也可以存储在table字段中.
a={p=print}
a.p("hello world")

输出hello world

  1. 在Lua中,函数具有特定的"词法域",这是指一个函数可以嵌套在另一个函数里,内部函数可以访问外部函数的变量.
a={p=print}
print=math.sin
a.p(print(1))

输出0.8414709848079

  1. sort排序函数

假设有一个table如下

network={
{name="a",IP="1"},
{name="b",IP="2"},
{name="c",IP="3"},
{name="d",IP="4"},
}

如果想以name为字段,按反向的字符顺序来对这个table排序的话

table.sort(network,function(a,b) return (a.name>b.name) end)

定义递归的局部函数时要注意!

local fact=function(n)
if n==0 then teturn 1
else teturn n*fact(n-1)
end
end

错误!!!

local fact 
fact=function(n)
if n==0 then return 1
else return n*fact(n-1)
end
end

正确!!!
一般先定义一个局部变量,再定义函数本身

  1. 尾调用不耗费栈空间
    这里注意尾调用的判断:只有当一个函数在调用完另一个函数之后,没有事情做才是尾调用.(可以是非常复杂的函数)
function f(x) return g(x) end

所以一个程序可以拥有无限个尾调用,在调用以下函数时,传入任何数字作为参数都不会造成栈溢出

  1. 一个迭代器结构通常涉及到两个函数:迭代器本身和一个用于创建该迭代器的工厂函数
function values(t)
local i=0
return function() i=i+1 return t[i] end
end

在该例中,values就是一个工厂

  1. 泛型for的语法如下:
for <var-list> in <exp-list> do
<body>
end

其中, var-list是一个或多个变量名的列表,以逗号分离:exp-list是一个或多个表达式,以逗号分离
下面是一个例子

for k,v in pairs(t) do print(k,v) end

一般来说,变量列表也只有一个变量

  1. 变量列表的第一个值成为"控制变量",该值绝不会为nil,因为当它为nil时,循环就结束了

  2. 在Lua中,数字,字符串都是可以连接的,但是对于两个table类型则不能直接相加.但是可以通过元表来修改一个值的行为.比如,现在有两个table类型的变量a和b,可以通过metatable定义表达式a+b.
    按照以下步骤进行:
    1)先判断a和b两者之一是否有元表
    2)检查该元表中是否有一个叫__add的字段(注意是两个下划线
    3)如果找到该字段,则调用,这个值对应的是一个metamethod
    4)调用__add对应的metamethod计算a+b的值

  3. 使用setmetatable来设置一个table或userdata类型变量的元表,

t = {}
local t1 = {}
setmetatable(t, t1)
print(getmetatable(t))
print(t1)

将t1设为t的元表 可以发现输出结果一样

输出为
table: 001F9558
table: 001F9558

  1. 在默认情况下字符串库为所有的字符串都设置了一个元表,而 其他类型在默认情况下则没有
print(getmetatable("Hello World"))
print(getmetatable(10))

输出为
table: 00B29918
nil

  1. 函数print总是调用tostring来格式化其输出
print({})

输出为
table: 00CF93A0

  1. 当访问一个table中不存在的字段时,这些访问会促使解析器去查找一个叫__index的元方法.如果没有__index这个元方法,那么返回值为nil.否则就由这个元方法来提供结果.__index元方法还可以是一个table.
Windows = {} 
Windows.default = { width = 100}
Windows.mt = {} 
function Windows.new(o)
     setmetatable(o, Windows.mt)
     return o
end
Windows.mt.__index = function (table, key)
     return Windows.default[key]
end
local win = Windows.new({x = 10, y = 10})
print(win.x)  
print(win.width) 

输出结果为
10
100
因为第二个执行了__index元方法

  1. __newindex元方法用于table的更新,而__indexx用于table的查询.调用rawset(t,k,v)可以绕过元方法来直接设置table t中key为k的value v.
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值