【Lua学习笔记】 --> 《类型与值、表达式与基本语法》

开学要去魔都某游戏公司实习了,客户端要用到lua语言,因此寒假前在学校借了《Lua程序设计》,这本书用来入门挺不错的~



类型与值

在lua中,有以下类型:



在Lua语言中,只有nil和false为假(false),其他都为真(true),包括0和空的字符串也是真

nil

在全局变量和table中,nil可以起到删除作用,一个全局变量在没有赋值前为nil,为一个已经赋了值的全局变量和table表里的一个变量赋值nil,相当于删除它们:



number

Lua中的数值没有像C/C++语言中那样,有整形、浮点型这么多分类,Lua只有一种类型就是number -- double类型。
以下几种都被看做 number类型
print(type(2))
print(type(2.2))
print(type(2e+1))
*注: lua中type函数用来返回参数的类型,它返回的类型是一个字符串。

string

lua是8为字节,所以字符串可以包含任何数值字符,包括嵌入的0。Lua中的字符串是不可修改的,可以创建一个新的变量来存放用户想要的字符串:
a = "hello world"
b = string.gsub(a, "hello", "hi")
print(a) --> hello world
print(b) --> hi world

Lua语言可以用两个双引号" "来表示字符串,也可以用两个单引号' '来表示,在双引号表示的字符串中如果有双引号,则需要用转义符表示,即:\"表示"

Lua中的转义序列有:



还可以在字符中用\ddd(ddd为三位十进制数字)的方式来表示字母: "alo\n123\""和'\97lo\10\04923"'是相同的.

还可以使用 [[ ... ]] 来表示“一块”字符串:

html = [[
<html>
<head></head>
<body>
    <a href="http://www.w3cschool.cc/">w3cschool菜鸟教程</a>
</body>
</html>
]]

这种形式的字符串可以包含多行,可以嵌套且不会解释转义序列,如果第一个字符是换行符则被忽略。

运行时,Lua会在string和number之间自动进行类型转换,当一个字符串使用算数操作符时,string被转成数字:

print("10" + 1) -->11
print("10 + 1") --> 10 + 1
print("hi" + 1) -->ERROR

Lua可以使用 ".." 来 将字符串连接,因此:

print(10 .. 20) -->1020

要注意的是, .. 前的数字必须和..之间有空格,不然lua解释器会认为是小数点


tonumber()可以将一个字符串转换为数字,tostring则可以将一个数字转换为而字符串:

print(tostring(10) == “10”) -->true
print(20 == tonumber("20")) -->true


Function

在lua语言中,function是第一类值(和其他变量相同),意味着函数可以存在变量中,可以作为函数的参数,也可以作为函数的返回值。lua可以调用lua或C实现的函数,因为Lua所有标准库都是C语言实现的。

userdata和thread

userdata 是一种用户自定义数据,用于表示一种由应用程序或 C/C++ 语言库所创建的类型,可以将任意 C/C++ 的任意数据类型的数据(通常是 struct 和 指针)存储到 Lua 变量中调用。

在 Lua 里,最主要的线程是协同程序(coroutine)。它跟线程(thread)差不多,拥有自己独立的栈、局部变量和指令指针,可以跟其他协同程序共享全局变量和其他大部分东西。

线程跟协程的区别:线程可以同时多个运行,而协程任意时刻只能运行一个,并且处于运行状态的协程只有被挂起(suspend)时才会暂停。


table

table(表)类型实现了”关联数组“,和C++里面的map非常相似,但是个人感觉还是Lua里的“关联数组”更灵活、更好用一些。C++中的map<key, value>,是模板类,在实现时,它里面所有的key的类型都是一致的,比如说 :std::map<std::string, int> mp;   在这之后insert一对“key-value”时,key的类型必须是string类型(或者能通过相关函数转换为string); 而Lua中的“关联数组” table,则没有这个限制,不仅可以通过整数来索引它,还可以使用字符串或其他类型的值(当然了,除了nil)来索引。table没有固定的大小,可以动态的往一个table中添加任意的元素。

在Lua中,table既不是“值”也是不是“变量”, 而是“对象”。 table就像是一个动态的对象,程序仅持有一个对它们的引用(或指针)。在Lua中不需要声明一个table,事实上也没办法声明它,我们可以通过“构造表达式”来完成一个table的定义,最简单的就是一个空的大括号:{}

a = {}
k = "x"
a[k] = 10
a[20] = "hello"
print(a["x"]) --> 10
k = 20
print(a[k]) --> "hello"
a["x"] = a["x"] + 1
print(a["x"]) --> 11

table永远是”匿名的“, 一个持有table的变量与table自身之间没有固定的关联性:

a = {}
a["x"] = 10
b = a --> b和a引用了同一个table
print(b["x"]) --> 10
b["x"] = 20
print(a["x"]) --> 20
a = nil --> 现在还有b在引用table 
b = nil --> 再也没有对table的引用了

一个程序中再也没有对一个table的引用时,Lua的垃圾收集器最终会删除该table,并复用它的内存。


a = {}
a["x"] = 10
print(a["x"]) --> 10
print(a["y"]) --> nil

当table中的某个元素没有初始化时,它的值为nil。 也可以像全局变量一样,赋予table中某个元素为nil,从而删除这个元素。

table中对于诸如a["name"] 的写法提供了一种更简便的方式,可以直接输入 a.name。因此,可以这样写:

a.x = 10
print(a.x) --> 相当于a["x"]
print(a.y) --> 相当于a["y"]

需要注意的是,a.x 和 a[x] 不相同, a.x 的意思是 a["x"] ,是以x为索引; 而a[x]的意思是以x的值为索引,假如x的值为10,则a[x]表示a[10]。

a = {}
x = "y"
a[x] = 10
print(a[x]) --> 10  即a["y"]字段
print(a.x) --> nil  a中没有"x"这个索引
print(a.y) --> 10

在Lua5.1中,"#"可以返回一个数组或线性表的最后一个索引值(或为其大小)。例如:

for i = 1, 10 do
	a[i] = io.read()
end
--上面也可以这么写
for i = 1, 10 do
	a[#a + 1] = io.read()
end

-- 打印读到的所有内容
for i = 1, #a do
	print(a[i])
end

其他一些#的用法:

print(a[#a]) --> 打印列表a的最后一个值
a[#a] = nil --> 删除最后一个值
a[#a + 1] --> 将v添加到列表末尾


数组实际上是一个table,当用#来计算大小时,有时候会有意想不到的结果:

a = {}
a[1] = 1
a[10] = 10
print(#a) --> 1

而数组的实际大小为2,这是因为#计算到第一个nil值之前,当一个数组中间有“空隙”, 即中间含有nil时,#就认为数组就这么大了。这跟我们的初衷可能不太一样。

我们可以使用table函数maxn,它返回一个table的最大索引数:

print(table.maxn(a)) --> 10

关于table还有很多内容,后面再从长议论。


表达式

算数运算符

假如A为10, B为20:


关系运算符



这些操作符返回true或者false。 == 和 ~=比较两个值,如果两个值类型不同,Lua认为两者不同; nil只和自己相等;Lua通过引用来比较table、userdata和function,也就是说当且仅当两者引用同一个对象时才相等。

a = {}; a.x = 1; a.y = 0
b = {}; b.x = 1; b.y = 0
c = a
print(a == c) --> true 引用同一个对象
print(b == c) --> false

Lua比较数字时按传统的数字大小进行,比较字符串按字母的顺序进行。

"0" == 0 --> false
2 < 15 --> true
"2" < "15" --> false  

最后一个是比较两个字符串,因为"1"比"2"小,所以"2"应该大于"15"。


 逻辑运算符

设定A为true,B为false


逻辑认为false和nil为假,其他为真,0也是true。

a and b -->  如果a为false,则返回a,否则返回b

a or b     --> 如果a为true,则返回b,否则返回b


print (4 and 5) --> 返回5
print (nil and 5) --> 返回nil
print(4 or 5) -->返回4
print(false or 5) --> 5

很实用的一个技巧,当x为false或nil时,将a赋给x

x = x or a

C语言中的三目运算符 a ? b  : c ,在Lua中可以这么写:

(a and b) or c

a为true,则(a and b)的值为b,与c作 or运算,返回b;

a为false,则(a and b)的值为a,  与c作or运算,返回c。


not的结果一直返回true或false

print(not nil) --> true
print(not false) -->true
print(not true) -->false
print(not 0) -->false

运算符优先级(由高到低)




基本语法

赋值语句

赋值是改变一个变量或表域最基本的方法:
str = "hello" .. "world"
t.n = t.n + 1

Lua语言中,还可以对多个变量同时赋值, 变量列表和值列表用逗号隔开,赋值语句右边的值依次赋值给左边的变量:
a, b = 10, 20 --> a为10,b为20

可以利用这个特性来进行交换操作:
x, y = y, x

赋值语句会先计算右边所有的值,然后进行赋值。
当变量个数和值的个数不一样时,Lua采取以下策略:


控制语句结构

与逻辑运算一样,控制语句的条件表达式认为false和nil为假,其它值为真。

if语句

有三种形式:
if conditions then
then-part
end


if conditions then 
then-part
else
else-part
end

if conditions then
then-part
elseif conditions then
elseif-part
.. --> 多个elseif
else
else-part
end

while语句

while conditions do
statements
end

repeat-until语句

repeat
statements
until conditions

如果condition为真,则退出语句。


for语句

第一类:数值for
for  var = exp1, exp2, exp3 do
loop-part
end

exp1为var局部变量的初始值,exp2为终止值,exp3为步长, exp3默认为1.

三个表达式exp只会被计算一次,在循环开始之前。


第二类:泛型for


① for k, v in ipairs(t) do print(k .. v) end

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

t为table类型


第一类泛型for,用于遍历数组,而且下标从1开始并且是连续索引值的数组。



如果索引值不是数字,或者不连续,它都只打印从索引1开始连续的部分:



第二类泛型for则可以打印出所有的元素,但是顺序不规则:



可见,它打印的顺序似乎并不是我们添加的顺序,因为table用哈希表实现,对于非数组形式的table,打印出的顺序和添加的顺序就不一样了。



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值