数据类型
Lua语言的数据类型非常丰富,包括nil、boolean、number、string、userdata、function、thread 和 table等类型。Lua中所有的数据类型的默认值都是nil。
nil
只有一个值,就是nil本身。
boolean类型
跟其他语言一样,包括false和true俩个值。 在lua语言中,只有nil和false的值为“假”,其他的都是“真”
number类型
number类型表示双精度浮点数字,lua中没有整数类型,所有的数字类型都是number,这个跟js其实是一样的。 我们可以省略小数部分和指数部分,下面这些都是有效的number类型。
4 0.4 4.57e-3 0.3e12 5e+20
string类型
首先String在lua中是不可能的值,这个跟大多数语言中的string类型设计是一样的,比如Java和JavaScript,Go等等(C语言的string是可变的)。 所以,如果在lua中你需要修改一个字符串,你可以像下面这样,重新生成一个新的字符串。
a = "one string"
b = string.gsub(a, "one", 'another') -- 讲one替换为another
print(a) --> one string
print(b) --> another string
注意看上面的代码,单引号和双引号都可以表示一个字符串。这点跟js也一样。
在lua中,lua会自动管理字符串的内存释放和回收,所以不用担心内存问题。
在lua中,字符串里面可以包含转义字符,和js不同的是,lua中可以使用转义的数字来表示ASCII编码。举个例子:
"alo\n123\""
'\97lo\10\04923"'
上面这两个字符串是相等的,因为a的ASCII码是97,换行符\n的ASCII码是10,数字1的ASCII码是49。所以上面的两个字符串是完全一样的。
lua中如果想表示多行字符串,可以使用[[...]],并且可以嵌套。但是这种字符串表示,不会去解析转义字符。
[[
<div>
<span>hello</span>
<p>
....
</p>
</div>
]]
lua中对于字符串的任何数字操作,都会尝试将字符串转换为数字类型。
print("10" + 1) --> 11
print("10 + 1") --> 10 + 1
print("-5.3e-10"*"2") --> -1.06e-09
print("hello" + 1) -- 错误:stdin:1: attempt to perform arithmetic on a string value
print(1 + "hello") -- 错误:stdin:1: attempt to perform arithmetic on a string value
这里跟js里面还是有区别的,js里面,第一个会输出“101”,第四个会输出“hello1”,第五个会输出“1hello”。
与上面相反,lua中对于数字的任何字符串操作,都会讲数字转换为字符串。
print(1 .. 3) --> 13
这里的..是lua中的字符串相加的操作。注意..前的空格,否则会被当做是前一个数字的小数点。后面的空格没有关系。
对于上面,你会觉得lua中的字符串和数字会自动转换,那比较的时候,是否也会自动转换呢?答案是不会转换。
print(1 == "1") --> false
我们知道在js里面如果使用1=='1'来判断是否相等,会返回true,必须使用===来使用强相等的判断,这点lua中不需要。lua中会直接判断类型是否相同, 如果不同直接返回false。\
如果需要字符串和数字比较,那就需要先将字符串转换为数字或者将数字转换为字符串:
print(1 == tonumber('1')) --> true
print(tostring(1) == '1') --> true
tonumber和tostring不用说你也知道是干嘛的。 官方文档:www.lua.org/pil/2.4.htm…
Table类型
lua中的table类型有点类似js中的对象,但是比js中的对象更加强大。它可以表示数组,set,队列等各种数据结构。lua中的table是引用类型,这意味着不会存在数据复制和拷贝的问题。操作table就是在操作指针,背后也没有副本或者新table的创建。
声明一个table:
a = {} --> 声明一个table
然后可以给这个table各种操作:
a[1] = "1"
a["k"] = "v"
基本上你在js里面怎么使用对象,这里就可以怎么使用lua的table,是不是很简单?
再来看个例子:
const a = {};
a['1'] = 1;
a[1] = 2;
console.log(a[1]) // 2
console.log(a['1']) // 2
a = {}
a['1'] = 1
a[1] = 2
print(a[1]) --> 2
print(a['1']) --> 1
注意上面这一个区别,js中是会将key转换为字符串的。而在lua中,是不会的。
除了上面这种a[1]形式访问table中的属性外,还可以通过a.x,a.y的形式访问,但是注意,x,y不能是数字。所以上面的a[1]和a['1']都不能使用这种形式。
注意: a.x和a.y这种形式,是通过x,y的值去访问table中的属性,而a[x]和a[y]是通过x,y本身作为索引去访问table,这里是有区别的:
x = 10
a = {}
a[x] = 1
a.x = 2
print(a[x]) --> 1,这里的key是10
print(a.x) --> 2,这里的key是“x”
这个跟js里面是一样的。
遍历table
a = {}
a[0] = 'one'
a[1] = 'two'
a[2] = 'three'
for i,line in ipairs(a) do
print(i .. '-->' .. line)
end
上面的代码输出如下:
1-->two
2-->three
为什么0不见了呢?因为在lua语言中,索引是从1开始的,这是一个约定,所有内建的函数和功能都是这个约定。 上面的代码你可以通过a[0]来显示访问到这个值。不过建议不要这么做。
function类型
function类型是lua中的一等公民。嗯,js里面是不是也是这样?
声明一个函数:
function add (a)
local sum = 0
for i,v in ipairs(a) do
sum = sum + v
end
return sum
end
函数调用:
a={}
a[1]=1
a[2]=2
add(a) --> 3
userdata类型
这种类型是专门用来在lua中表示由C语言创建的各种数据类型的。这里就先不看, 因为很少需要用到这个。
thread类型
在lua中,有一个coroutine(协程)的概念,他跟线程有点类似,lua中的协程有自己的局部变量,但是共享所有的全局变量。在同一时间只会执行一个协程,这点跟线程是不一样的,线程是同一时间会执行多个线程。
协程的使用
co = coroutine.create(function ()
print("hi")
end)
print(co) --> thread: 0x8071d98
print(type(co)) --> thread
在coroutine中,有一个create函数。通过这个函数可以创建出一个thread类型变量,注意这里表示创建了一个协程。
协程的状态
lua中的协程有3种状态,suspended,running,dead。 刚刚创建的协程的初始化状态是suspended,也就是说协程不会自动的运行,可以通过下面的代码查看协程的状态。
print(coroutine.status(co)) --> suspended
启动一个协程
使用以下代码来启动一个协程:
coroutine.resume(co) --> hi
print(coroutine.status(co)) --> dead
协程的暂停与运行
在js中我们知道,有一个关键字yield,用来暂停生成器函数的执行。举个例子,
function *test(){
yield 1
yield 2
return 3
}
const testGe = test();
testGe.next() // {done: false, value: 1}
testGe.next() // {done:false, value: 2}
生成器函数test被调用的时候回返回一个生成器。这个生成器每次调用next的时候 就会执行函数的代码,直到遇到yield关键字就暂停执行。
类似的,在lua中也有yield,我们来看个例子:
co = coroutine.create(function ()
for i=1,10 do
print("co", i)
coroutine.yield()
end
end)
看上面的代码,当我们执行coroutine.resume(co)的时候,都会执行协程中的代码,但是当遇到coroutine.yield()的时候灰停在协程的执行。
运行一次的输出结果:
coroutine.resume(co) --> co 1
print(coroutine.status(co)) --> suspended
运行第二次:
coroutine.resume(co) --> co 2
print(coroutine.status(co)) --> suspended
发现没有,这里和js中的生成器函数那货是不是非常的类似? 肯定的,你运行10次之后,再去查看co的状态,肯定是dead状态了。你自己去试试吧。
使用了yield的协程函数内部,怎么传递参数呢?看下面的例子:
co = coroutine.create(function (p)
for i=1,10 do
coroutine.yield(p + i)
end
end)
在上面的例子中,我们给协程函数添加了一个参数p,并且在调用coroutine.yield的时候,执行p+i的表达式,这个表达式执行的结果,就是该次执行协程的返回结果。
我们来看下: 第一次运行:
print(coroutine.resume(co, 1)) --> 2
第二次运行:
print(coroutine.resume(co, 1)) --> 3
看到这里你应该明白了,每次执行resume的时候,都是执行到yield位置暂停,然后执行yield中的表达式,然后将结果返回。 官方文档: www.lua.org/pil/9.html
原文地址:codebe.org