lua学习的查缺补漏

3.8k 词

目录

  1. 多行注释
  2. 取整
  3. 长字符串
  4. 字符串标准库
  5. lua中安全访问
  6. 可变长参数
  7. 输入和输出
  8. lua运行一段程序

认真学习,增强自己的能力和知识面。

多行注释

1
2
3
4
--[[
fdsa
fdas
]]

取整

为了做到公平性取整,应该做到3.5+0.5为偶数则进位,而2.5+0.5为奇数不进位。

1
2
3
4
5
6
7
8
function round(x)
	local f = math.floot(x)
	if	(x == f) or (x % 2.0 == 0.5) then
		return f
	else
		return math.floor(x + 0.5)
	end
end

长字符串

在lua中字符串是常量,一个字符串当被存到内存中的时候就不能再被改变了,所以我们发现如果一个变量引用了一个字符串,我们是不能像CC++那样通过索引进行改变其值的,只能从新赋值新的字符串,这样子其实是这个变量指向了另一块内存了。

1
2
3
4
5
6
local page = [[
fdsaf

fdasf

]]

字符串标准库

1
2
3
4
5
6
7
8
9
10
11
12
13
string.gsub("one string","one","two") --> two string
string.rep("abc",3)
string.reverse("abc")
string.lower("Abc")
string.upper("abc")

string.sub("abc",1,2) –包含1和2
string.char(97) – a,转换字符及其内部数值表示形式
string.byte(a) – 97

string.find("hello world", "wor") –7 9
string.gsub("hello world", "l", ".") –he…o wor.d

一般情况下,string内部的函数都是针对于字节进行操作的,当遇到中文就不行了,在这里lua增加了utf8的函数封装。

1
2
3
4
5
6
7
8
local s = "中华人民共和国"
utf8.len(s) --7,返回指定字符串中UTF-8字符的个数
--utf8把字符位置转换成字节位置
print(utf8.codepoint(s,utf8.offset(s,1),utf8.offset(s,2))) -- 
print(utf8.char(20013,21326))
print(utf8.offset(s,3))
print(string.sub(s,1,utf8.offset(s,3) - 1 )) --在使用的时候需要注意,offset返回的是字符的第一个字节位置,在截取的使用时候需要减去1
print(3.5 % 2)

lua中安全访问

通过 (class or {}). 的方式来实现安全访问

表的拷贝除了使用遍历赋值之外,还可以通过table.move函数来实现。

在这里注意到下面的代码,如果我将table插入到另一个table中,这里是引用,而不是新开辟了一块新的内存,如果我现在改变inta中index为1的值,那么表a中index为1的表的index为1的值也会随着改变。

这里还需要思考一个问题,什么时候一个变量才算引用一个表成功呢?意思是这两个变量是否指向同一块内存,一般我们常说基本类型一般是不会引用的像数值和布尔,这里table会被引用,

1
2
3
4
5
6
7
8
9
10
table.move(a,1,#a,1,{})

local inta = {1,2,3}
local a = {}
local b = {}
for i = 1, 3 do
table.insert(a,inta)
end

table.move(a,1,#a,1,b)

通过’#’符号对表进行取长度,只适应于数组,不适应于hash表,当表中存在空洞的时候,不要再使用’#’来取长度了,在对数组进行添加和移除的时候,应该使用remove和insert函数,而不应该直接赋空值。

这里常见的误区包括:

  1. 对一个数组中的某个索引进行完赋空值操作之后,还使用ipairs进行遍历,因为存在空洞,所以是不可能遍历整个数组的。
  2. 一次遍历删除数组中的多个值,这样子可能会导致删除不干净,当连续两个相同的值需要删除的时候,后面那个值是删除不掉的,因为他的索引值已经减一了,到了刚删除值的位置了。这样子是遍历不到它的。

要怎么解决这个问题呢?

如果删除之后不保留数组的特性,那么直接遍历一遍删除的赋值为nil就行了,但是一般很少不保留,所以应该使用下面这种方法,那就是创建一个新表,删除的不插入其中,不删除的插入其中,然后赋值给原来的变量。

可变长参数

在函数中,一个函数为了可以接受可变长的参数列表,一般采用三个点。

用这个三个点获取来的参数列表其实是一个表达式,和return回来多个值是一样的,可以选择接受一个或者多个,也可以通过表的形式全部接受。

但是如果可变长参数中包含无效的nill,那么{…}获得的表可能不再是一个有效的序列。这样会导致一个问题,就是table中存在nil的时候,元素就会被自动移除。假设参数为 1,nil,2,那个打包到table中就只剩下1,2了,table的长度为2,不是一个数组,因为table[2]没有这个键值。

这个时候我们可以使用table.pack来打包可变长参数。通过pack打包出来的表会存在一个键值n,表示原来 … 返回来的参数个数。

通过table.unpack可以解开表,返回内容类似于return表达式。

输入和输出

如果没有重定向io.lines(),默认会从控制台接收输入,运到换行符不会结束,会以CTR^Z结束。

io.input和io.output可以用于改变当前的输入输出流。调用io.input(file_name)会以只读模式打开指定的文件,并将文件设置为当前输入流。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
local file = io.open("a.txt","r")

io.read() –类似于c中的cin函数
io.write()–类似于c中cout函数

local t = {}
for line in io.lines() do
table.insert(t,line)
end

local temp = io.input() –保存当前的输入流
io.input("newinput") –打开一个新的当前输入流
对新的输入流进行某些操作
io.input():close() –关闭当前流
io.input(temp) –回复此前的当前输入流

print(os.execute("ls"))

io.read(args)实际上是io.input():read(args)的简写。

io.write((args)是io.output():write(args)的简写。

为了及时的获取输入流中的内容,可以使用io.flush()函数刷新输入流。

我们可以使用os.excute(“ls”),来展示目录中的文件。

lua运行一段程序

突然发现自己用多了编译器竟然不知道lua是怎么运行一段程序的了,一般lua运行程序分为两种:

1
2
3
lua -i prog --运行prog这个文件的带码,并进入交互模式

dofile("lib1.lua") –在交互模式下加载文件

函数dofile在开发阶段非常有用,我们可以通过它重新加载带码,这样就可以使用新的代码了。

使用方法如下:

  1. 加载一个文件: dofile(“hello.lua”)
  2. 调用文件中的函数
  3. 修改文件中的函数
  4. 重新加载文件: dofile(“hello.lua”)
  5. 调用函数:就会发现输入的内容使我们新修改的内容

而且lua存在独立的解释器类似于,这个就像是通过命令行执行一个c程序一样,lua命令的完整参数形式如:

lua [options] [script [args]]

  1. -e参数允许我们直接在命令行中输入代码
  2. -l参数用于加载库。
  3. -i参数用于在运行完其它命令行参数后进入交互模式

%lua -e “sin=math.sin” script a b

在上面的用例中,编译器在运行代码前会创建一个名为arg的边,其中存储了所有的命令行参数。索引0中保存的内容为脚本名,索引1保存的为第一个参数。所以上面的例子解释如下:

  1. arg[-3] = “lua”
  2. arg[-2] = “-e”
  3. arg[-1] = “sin=math.sin”
  4. arg[0] = “script”
  5. arg[1] = a
  6. arg[2] = b
1
2
3
4
5
6
7
8
9
10
11
12
local function printParams(arg)
    for i, v in ipairs(arg) do
        print(v)
    end
end

printParams(arg)

print(sin(12))

–lua -e "sin=math.sin" hello.lua 1 2

            <hr style="visibility: hidden;"/>
            
            <hr style="visibility: hidden;"/>