1.从hellowrold开始
--语法和Python比较类似,直接像Python一样使用print即可
--这里我可以直接写中文,显然被当成了注释。在lua中,两个-表示注释
--[[
这种形式可以表示多行注释
]]
--在lua中,语句后面也可以像Python一样加分号,但也可以不加。
print("hello world")
2.lua的基本类型
--lua和Python一样,并不需要像C一样声明一个变量,因为本身带有值的类型
--直接给变量赋值即可
--[[
lua的基本类型有:nil(空)
boolean(布尔)
number(数字)
string(字符串)
table(表)
函数等内容后面再说
]]
--[[
注意:赋值的时候,可以将多个语句写在一行,用空格或者;分隔。
这里只是演示,但是实际开发中不建议这么做
]]
a = ;b="satori";c=3.14;d=math.pi
--使用type查看值的类型
print(type(a), type(b), type(c), type(d)) -- number string number number
--可以看到,lua中没有什么int float等等,只要是数字,类型通通为number
print(type(print)) -- function
--如果一个变量我们没有赋值直接使用的话,在Python中会报错,提示name xxx is not defined
--但在lua中不会报错,对于一个没有赋值的变量在lua中默认为nil
--nil用于区别其他变量,给一个全局变量赋值为nil等于删除这个全局变量
print(mmp, type(mmp)) -- nil nil
--在lua中,只有false和nil表示假,其他的都表示真。0和空字符串在lua中表示真,这和Python不太一样
--lua中,字符串一旦创建了,便不可以修改了。这和Python一样,但是在Python中可以使用replace修改并返回一个新的字符串
--那么lua也有类似的方法,该方法同样会得到一个返回值,不会修改原来的值
s1 = "hello cruel world"
s2 = string.gsub(s1, "cruel", "beautiful")
print(s1) -- hello cruel world
print(s2) -- hello beautiful world
--并且在lua中,可以使用单引号也可以使用双引号
--类似于Python,如果输入的字符串本身有单引号,那么外部就用双引号,反之亦然
print("I'm satori") --I'm satori
--如果我非要使用相同的引号,那么可以使用转义字符,将内部的引号进行转义
print('I\'m satori') --I'm satori
--[[
一些转义字符
\a:响铃
\b:退格
\f:提供表格
\n:换行
\r:回车
\t:制表 ]]
print("i am \r satori, come from \n东方地灵殿")
--[[
satori, come from
东方地灵殿 ]]
--字符串也可以使用\加上三位数字表示,就是相应的ascii表
print("\065") --A
-- 如果想表达多行字符串,可以使用[[ ]],类似于Python中的三引号''' '''
s3 = [[
南村萝莉欺我老无力
经常与我发生性
关系
]]
print(s3)
--[[
南村萝莉欺我老无力
经常与我发生性
关系
]]
--如果一个字符串和一个数字进行运算的话,那么会尝试将字符串转化成数字
--显然字符串必须是由数字组成,如果包含不是数字的字符,就会报错,无法转化
)
--字符串的连接,在lua中..表示字符串连接
--不可以使用"a"+"b"这样的形式,这在Python中是允许的,但在lua中不可以。但可以使用..
s4 = " satori"
print("a".."b"..s4) --ab satori
") -- 1+1 == 2
-- 如果我想获取一个字符串的长度该怎么办呢?在Python中使用len函数,但在lua中使用#。
-- 而#在Python中表示注释,因此两门语言某些地方类似,某些地方又完全不同,确实很有意思
-- 输出结果为45,咦,不是15吗?肯定一眼就找出答案了,一个汉字占三个字节
-- 而且lua默认用的是utf-8编码。值得一提的是,在Python中使用len函数计算出来的结果为15
-- 因为在Python中,len计算的是字符数,而不是字节数。
-- 而且在go语言中,计算的结果也为45,同样是字节。如果想得到字符数,在go中需要用[]rune转化一下。
s6 = "mmp"
-- lua中还有一种叫做table的类型,说白了就是Python中的字典(哈希表),key和value一一对应
hash_map = {}
hash_map["satori"] = "东方地灵殿"
print(hash_map["satori"]) -- 东方地灵殿
-- 将hash_map赋值给别的变量,并且将hash_map删除
hash_map_1 = hash_map
hash_map = nil
print(hash_map) -- nil
print(hash_map_1["satori"]) -- 东方地灵殿
-- 可以看到即使删除了hash_map,但不会对hash_map1造成影响
-- lua的垃圾回收采用的是标记清除,当hash_map1也赋值为nil,没变量再引用的时候就会删除垃圾资源
--如果访问一个不存在的key,那么得到的会是nil
x = {}
x[] =
x[] =
], x[], x[]) -- 2 3 nil
--想删除table中某个元素,直接赋值为nil即可
x[] = nil
]) -- nil
-- 而且table这种结构,还可以使用.来访问
x.name = "satori"
print(x.name) -- satori
3.操作符
--1.算术操作符
a =
b =
print(a/b) --7.5,这里和Python3一样,不是地板除,而是会包含小数部分
--这里值得注意的是,Python中平方是**,而lua中是^
--2.关系操作符
>) -- true
<) -- true
>=) -- true
<=) -- true
==) -- true
--注意:不等于在Python中是!=,但在lua中是~=
~=) -- true
--3.逻辑操作符, 这个和Python类似,有and,or,not
a1 =
a2 = -- 别忘了0在lua中表示真,这和Python不一样
a3 =
b1 =
b2 =
b3 = nil or false
--[[
对于a and b,首先and表示两边都为真整体才为真。如果a为真,那么还要判断b。a为假,b就不用判断了
因此对于 a and b,结果究竟是a还是b,其实不取决于b,而是取决于a。
如果a为真,那么由于and的特性,因此还要判断b,那么结果就为b,不管b是真还是假
如果a为假,那么由于and的特性,b不需要判断了,那么结果就为a
同理对于a or b也是一样。a or b表示两边都为假整体才为假
如果a为真,那么不管b是真是假,整体都为真,所以b无需判断,结果就为a
如果a为假,那么还要判断b,因此结果就是b。
因此在lua和其他语言一样,也存在着短路求值,当第一个条件已经能够决定整体的结果时,剩下的条件就不会再判断了
举一个C语言的例子
#include <stdio.h>
int main()
{
int a = 10;
if (1<0 && a++)
{
printf("你猜a的值为多少?\n");
}
printf("a=%d\n", a);
if (1<0 || a++)
{
printf("你猜a的值又为多少\n");
}
printf("a=%d\n", a);
}
第一次打印a的时候,值为10,因为1<0为false,所以a++无序判断,因此a++根本没有执行。
第二次打印a的时候,值为11,因此1<0为false,但是操作符是or,所以会判断a++,因此if语句执行完之后打印11
]]
print(a1, a2, a3) --5 4 nil
print(b1, b2, b3) --5 7 false
-- 那么对于4 and 5 and nil or 4 and 5 or 7,会打印什么结果
--[[
操作符从左往右看,4 and 5结果为5,5再and nil,结果为nil, nil 再or 4,结果为4, 4 and 5结果为5, 5 or 7结果为5
]]
)
--[[
我们也可以用这种方式来模拟三元操作符
v = a or b,如果a为真,v=a,否则等于b
v = a>b and x or y,如果a>b,结果为x。因为a>b为真,(a>b and x) == x, x又为真,那么or上y当然为x
如果a<b,结果为y。因此a<b,那么a>b为假,(a<b and x)==(a<b),一个假or上y当然为y
因此 v = a>b and x or y,就类似于C中v = a>b?x:y,类似于Python中v = x if a>b else y
]]
-- not就比较简单了,表示取反
print(not false) --true
) --false
print(not nil) -- true
print(not "satori") --false
--4.字符串的连接
--前面介绍过可以使用..连接字符串
print("宇宙には始まりはあるが".."、終わりはない".."、無限") --宇宙には始まりはあるが、終わりはない、無限
print("星にもまた始まりはあるが".."自らの力を持って滅び逝く".."有限") --星にもまた始まりはあるが自らの力を持って滅び逝く有限
-- 如果字符串和数字拼接,那么会自动将数字转化成字符串
a =
print("96猫@"..a.."cm") --96猫@142cm
--[[
这里需要注意的是,我们是用a表示142,也可以直接写上142
print("96猫"..142),也是合法的,但是,我要说但是了。
如果直接写上142的话,那么后面就不能再接..了,意思就是"96猫"..142是合法的,会得到96猫142,但是142.."96猫"是非法的。
如果将这个值赋值给一个变量,a = 142,那么"96猫"..a,和a.."96猫"都是合法的
]]
--5.操作符优先级
--[[
这个就不介绍了,跟其他语言类似。
总之一句话:如果不确定的话,那么使用括号就可以了
]]
--6.table构造式
days = {"星期一", "星期二", "星期三","星期四","星期五","星期六","星期日"}
--table每一个元素是由key和value组成的,而我们这里显然不是键值对的形式
--在lua中,在不指定key的情况下,可以使用索引来指定。但是比较恶心的是,索引默认是从1开始的,这个比较反人类。
--所以days[1]便是第一个元素,days[2]是第二个元素。感觉table既有点像数组也有点像字典
]) --星期一
]) --星期四
]) --星期日
--table还有一种构造形式
days = {name=, anime="东方地灵殿"}
--等价于:days={}; days.name="satori"; days.age=18; days.anime="东方地灵殿"
print(days.name, days.age, days["anime"]) --satori 18 东方地灵殿
--不管怎么创建,lua中的table和Python的dict一样,都可以*动态的添加或者删除。
--添加:直接写上key value即可,删除:直接令相应key对应的value等于nil即可
4.语句
--1.赋值
--首先lua和Python一样,可以进行多重赋值
a,b=,
print(a,b) --1 2
--也可以直接进行两数交换,而不需要中间变量
a,b=b,a
print(a,b) --2 1
--比较特殊的一点,当左边的变量和右边的值在数量上不匹配的时候
x,y,z = , --这句代码在Python中毫无疑问会报错,但在lua中不会
--当左边的变量数多于右边的值的时候,那么得不到值得变量会被赋值为nil
print(x,y,z) --1 2 nil
x,y = ,, --同样这句代码在Python中也会报错,但在lua中也不会
--当左边的变量数少于右边的值的时候,多余的值会被自动丢弃
print(x,y) --1 2
--但是值最好要匹配
--2.局部变量和块
--局部变量,声明一个局部变量只需要在变量前面加上local关键字即可,局部变量只在当前的语句块里面有用
--如果不加local,在while循环中新建一个y,那么while循环结束后,打印y,会打印循环里面给y赋的值。
--因为循环里面的y是全局的,会覆盖上面的y
x =
y =
do
y =
x = x+
end
--但是当我加上了local,会发现打印的还是40,因为局部变量不会对全局变量造成影响
--类似于Python中的函数,在函数中定义的变量,只要不加global关键字,都是局部变量
--并且Python无法在while循环中声明一个局部变量。循环,条件语句等等,对于Python来说,只有全局变量。但lua可以。
x =
y =
do
x = x+
end
var1 =
var2 =
> then
var2 =
end
--可以看到var1没被修改,var2被修改了。if里面的var1只在if里面有效,不会对外面的var1造成影响。而var2是会覆盖外面的var2的。
xxx =
then
print(xxx)
else
end
--如果if条件成立,会打印666,但是不成立,会打印123.
--但是如果我没在条件语句、循环等等中声明局部变量,而是在最外面声明一个局部变量呢?
> then
v =
end
--会发现这个局部变量,就等同于全局变量
--此外,我们还可以使用do end来声明一个语句块。当遇到lua解释器遇到do,会先找到对应的end,然后执行do和end里面的内容。
do
end
print(wanwan) -- nil
--由于我声明了do end,那么do end里面的局部变量是无法在外面被检测到的,所以打印为nil。
--值得一提的是,如果不加local,那么wanwan仍旧是一个全局变量,在外面还是可以访问的到的。
--局部变量会虽着作用域的结束而消失
--3.控制结构
--if条件语句,和Python比较类似。但是需要在条件语句结束后加上end,有点像Python的tornado框架里的模板语言。
--此外if条件后面还需要加上then
if false then
print("古明地觉")
>= then
print("芙兰朵露斯卡雷特")--芙兰朵露斯卡雷特
else
")
end
--此外,if语句还可以嵌套
gender = 'f'
age =
if gender == 'f' then
then
print("获取我们可以做一场交易")
then
print("虽然担些风险,但也值得一试")-- 虽然担些风险,但也值得一试
else
print("最低三年,最高死刑")
end
else
print("oh♂yeah SIR")
end
--此外,连接两个条件,lua中也使用and or关键字,而不是&&和||
--循环语句
x =
do
print(x)
x = x + --注意不可以写成x+=1的形式
--[[
10
11
12
13
14 ]]
end
-- 可以想象相较于Python,把:换成了do,并且在结尾加上了end
--并且在lua中还有一个repeat until,表示啥呢?从名字也能看出,重复····直到···
--不得不说,往往英语不是母语的人,发明出来的语言,关键字更清晰易懂。
x =
repeat
x = x+
print(x)
--[[
2
3
4 ]]
--这段代码表示啥呢?不断地重复x = x+1; print(x),直到x>3为止,你再往下走
--当然lua中还有for循环
--[[
结构:
for i=a,b,c do
<body>
end
这几行代码是什么意思呢?转化为while循环
i=a
while i<=b do
<body>
i = i+c
end
注意:如果c不指定,默认为1
]]
,, do
print(i)
end
--[[
1
4
7
10 ]]
--注意:for循环里面的i,只在for里面有效。for循环结束后,就被自动销毁了。
print(i) --nil
--for遍历table
t = {name=, gender="f"}
--和Python不一样,在lua中不能直接遍历,需要遍历pairs(table),可以只遍历key,也可以遍历key和value
for k,v in pairs(t) do
print(k,v)
--[[
gender f
name satori
age 18 ]]
end
--如果遍历的时候,同时指定索引
--此时的t就类似于数组,可以直接使用索引访问,但是从1开始,反人类
t = {"satori", "koishi","mashiro"}
]) --satori
for k,v in ipairs(t) do
print(k, v)
end
--[[
1 satori
2 koishi
3 mashiro ]]
--查找某个值所在的位置
days = {"星期一","星期二","星期三","星期四","星期五","星期六","星期日"}
for k,v in ipairs(days) do
if v == "星期三" then
end
end
--4.break和return
--break,跳出所在的循环, 如果外部还有循环则不会跳出。
--return,只能出现在函数里,结束函数并返回一个值
, do
then
break
end
print(i)
--[[
1
2 ]]
end
--return等介绍函数的时候再说
5.函数
--如何定义一个函数
--[[
函数结构:
function foo()
<body>
end
]]
function add(a)
b =
print(a+b)
end
add()
print(b) --11,这里打印11,说明能找到add函数里面的b,明明是在函数里面,函数结束了,居然没有被销毁。
--显然不加local,即使是在函数里,外部也能访问的到。
--像os.date(),math.sin()等等都属于函数
print(os.date()) --10/18/18 14:16:38
)) --0.5
--函数的传参
function foo(a,b)
print(a,b)
end
--这里foo函数需要指定两个参数,但如果我只指定一个会怎么样?指定三个又会怎么样
foo() --666 nil
--可见没有得到值的参数会等于nil
foo(,,) --666 777
--多余的值会自动丢弃,这在Python中是不允许的,该传几个就传几个
--类似于赋值a,b=1 ; x,y=1,2,3
--另一种传参方式
function foo(...)
local a,b,c=...
print(a,b,c)
end
foo(,,) -- 1 2 3
--函数的返回值,这个和Python一样,可以返回多个,比如string.find()函数
print(string.find("hello cruel world", "cruel")) -- 7 11
--这里有两个返回值,7表示cruel的开始位置,11表示cruel的结尾位置。当然索引是从1开始的,反人类。
--自己定义一个函数,接受一个数组,返回数组的最大值以及索引
function get_max_value(arr)
max = arr[]
ind =
for index, value in ipairs(arr) do
if value > max then
max,ind = value,index
end
end
return max,ind
end
,,,,,,,,,})) --42423 8, 索引从1开始,反人类
--首先函数即变量,函数也是可以直接赋值的
t = {a=print}
t.a("hello world") --hello world
math.sin, print = print, math.sin
)) --0.5
--可以看到进行交换之后,可以直接当做对方去使用。
--这里我们在交换回来,不然下面不好进行了
math.sin, print = print, math.sin
function foo()
return "古明地觉"
end
bar = foo
print(bar()) --古明地觉
--匿名函数,其实说白了还是普通的函数,只是可以写在一行,并且省了函数名
--类似Python里的lambda,只建议定义一些简单的逻辑。
foo = end
)) --4,
--使用function还可以对table里面的元素进行排序
--table.sort函数可以对一个table进行排序
girls = {
{name=},
{name=},
{name=},
}
--这个函数会直接在原table上进行修改
table.sort(girls, function(a,b) return (a.name>b.name) end)
for i,v in ipairs(girls) do
print(v.name)
--[[
satori
mashiro
koishi ]]
end
--[[
可以看到按照name从大到小排列了,a,b就代表了table里面的所有元素。每两个进行比较,a.name大的放在前面。
再比如Python:
girls = [
{"name":"satori", "age":18},
{"name":"koishi", "age":17},
{"name":"mashiro", "age":16}
]
girls.sort(key=lambda x: x["name"])
这个x就代表了girls里面的每一个元素,怎么排,按照x["name"]来排,这个默认是从小到大排
]]
--关于排序,还可以按照table去排序其他table,怎么理解呢?
girls = {"mashiro", "satori", "koishi"}
age = {mashiro=, satori=, koishi=}
--此时girls和age一一对应,我想age从小到大的方式排序girls
table.sort(girls, function (a,b) return age[a]<age[b] end)
], girls[], girls[]) --mashiro koishi satori
--计算导数
--导数公式,(f(x+d) - f(x)) / d ,这个d趋近于无穷小
function derivative(f, delta)
delta = delta or 1e-4 --这算是缺省参数,如果我们不指定,那么delta为nil和1e-4进行or运算,会等于1e-4
return function(x)
return (f(x+delta) - f(x)) / delta
end
end
--这里使用了闭包,闭包就是函数内部还嵌套一个函数,并且内部嵌套的函数,要引用外部函数的变量
foo = derivative(math.sin, 1e-5)
)) -- -0.83906880893325, 便是函数math.sin在x=10处的导数
function newCounter()
return function()
i = i+
print(i)
end
end
--内部的i是可以访问到外部的i的
f = newCounter() --此时的f就是闭包里面的那个函数
--显然这个i并没有被销毁,因为在外部有f指向内部的函数,因此没调用一次,i就会加1,这和go语言基本上一样
--和Python也有点相似,只不过Python中需要nonlocal关键字声明
f()
f()
f()
--函数递归,最经典的便是阶乘
function fac(x)
then
end
)
end
))
********)