lua进修之温习汇总篇
第六日笔记
1. 基本观点
程序块
定义
- 在 lua 中任何一个源代码文件或在交互形式中输入的一行代码
- 程序块可所以恣意大小的
- 程序块可所以一连串语句或一条敕令
- 也可由函数定义构成,平常将函数定义写在文件中,然后用诠释器实行这个文件
- 换行在代码中不起任何作用,只是为了提拔可读性
- 分开符 ; 起分开作用
a = a * 2
b = a * b
a = a * 2;
b = a * b
a = a * b; b = a * b
a = a * b b = a * b
交互形式
在交互形式中输入的一行内容会被诠释器看成一个完全的程序块,假如这一行的内容不足以构成一个完全的程序块,就会守候输入
退出交互形式
Ctrl + Z
是 end-of-file 掌握字符,在 dos 中是这个快捷键os.exit()
规范库中的退出函数
地区设置
- lua 中辨认什么是字母是经由历程地区设置来鉴别的
- 如设置希腊,就能够辨认希腊字母作为变量
- 但在不支撑该地区的体系上没法实行
实行函数文件
- lua 函数文件途径
dofile("文件途径 / 须要转义")
加载函数库
-- 阶乘函数
function fact(n)
if n == 0 then
return 1 --0 的阶乘是 1
else
return n * fact(n - 1) -- 3 的阶乘, 3 * 2 * 1
end
end
print("Enter a number:")
a = io.read("*number") -- 读取用户输入且需为数字范例的
print(fact(a)) --挪用阶乘函数,并传入实参 a
-- lib1 函数库
function norm(x, y)
return (x ^ 2 + y ^ 2) ^ 0.5 -- 两个数的平方和再开平方根
end
function twice(x)
return 2 * x -- 一个数的两倍
end
标识符
定义
- 由恣意数字、字母、下划线构成的字符串叫做标识符
- 标识符不能由数字开头
- 标识符不能以下划线开头后跟多个大写字母
- 如: _PROMPT, _VERSION
- lua 将它们保存用作特别用处,被称为哑变量
_PROMPT = ">lua" -- 修正交互形式中的提示符,默以为 >
保存字
流程掌握
if
then
elseif
end
for
do
in
while
repeat
until
if 前提表达式 then
elseif 前提表达式 then
end
for 掌握变量, 停止变量, 步长 do
<轮回体>
end
a = {}
for i,v in ipairs(a) do
<轮回体>
end
while i < 10 do
i = i + 1
print(i)
end
repeat
i = 0
i = i + 1
until i > 10
前提掌握
true
false
逻辑掌握
and
or
not
范例
function
local
nil
须要注重的点
nil == nil
是相称的and
和And
差别,lua 辨别大小写- lua 中前提值不单单议只要
true
和false
- 在 lua 中任何值除了
false
和nil
都能够用作示意「真」 - 包括空字符串
""
和数字0
解释
- 单行解释
--
- 多行解释
--[[]]
- 使多行解释中的代码见效
---[[ <代码块> --]]
- 多行解释中包括多行解释
--[==[ <多行解释> ]==]
全局变量
- 全局变量不须要声明,只须要将一个值赋给它即可
- lua 中能够接见一个未初始化的变量且不会发作毛病
- 但这个未初始化的变量的值为
nil
- 删除全局变量赋值
nil
即可 - lua 将全局变量存储在一个一般的 table 中
诠释器
参数
-i
先实行程序块,后进入交互形式-e
直接实行代码块-l
加载库文件
诠释器实行参数前
- 会先寻觅一个叫做
LUA_INIT
的环境变量 - 找到了,且内容为
@文件名
的话,就实行这个文件 - 没找到,就假定内容为 lua 代码, 并实行
诠释器运转剧本前
- lua 将剧本前的参数存储到 arg 这个 table 中,用作启动参数
- 剧本名在这个 table 中的索引为 0,厥后参数依此类推
- 剧本名前的参数为负数索引
lua -i -e "hello" script a b
arg[0] = "script"
arg[1] = "a"
arg[-1] = "hello"
arg[-2] = "-e"
arg[-3] = "-i"
- 在 lua 中也能够经由历程变长参数语法来检索剧本参数
- 变长参数为
...
三个点,作为函数参数通报时示意通报一切参数
2. 范例与值
- lua 是动态范例言语
- 每一个值都照顾有它的范例信息
猎取值的范例
type()
能够返回一个值的范例称号type()
的返回结果永远是string
范例的
print(type(3)) -- number
print(type("a")) -- string
print(type({"a", "b", "c"})) -- table
print(type(io.read)) -- function
print(type(true)) -- boolean
number
- 实数,即双精度浮点数
- 可运用科学计数法,如
2e2
示意 200 - 可从新编译 lua,运用其他范例的值来示意数字范例,如
long
tonumber()
用于将一个字符串显式的转换为数字范例
boolean
- 在 lua 中,有两个布尔值一个是
true
示意为「真」,一个是false
示意为「假」 - 但,这两个值不是用来示意前提的唯一值,在 lua 中 除
nil
和false
外的任何值,都能够用来示意「真」, 包括空字符串
""
和数字0
nil
- 只要一个值,
nil
- 仅用来示意为空,示意未初始化的变量或 table 元素
- 也可用来删除变量或 table 元素
string
- 是对象,由自动内存接纳器举行分派和开释
- 是字符序列,是8位编码
- 能够包括数值编码,如二进制
- lua 中的字符串是唯一不可变的值
..
字符串衔接符,用于衔接两个字符串,但数字范例运用时须要用空格离隔#
长度操纵符,后跟字符串,能够猎取字符串长度[[]]
在期内的特别字符不须要转义[==[ <多行解释> ]==]
能够准确打印多行解释的内容"3" + 4
如许的值会是number
范例,发作了运转时隐式转换
print("97" == "a") -- 在 ASCII 编码表中,97 示意为 a
print(type(3 .. "")) -- string
print(3..4) --报错
print(3 .. 4) -- 34
print(#"hello") -- 5
-- 猎取子串,证实字符串是不可变的值
a = "hello"
b = a .. " ,world"
print(a) -- hello
print(b) -- hello, world
a = [[
<html>
<head><title>芜湖</title></head>
<body></body>
</html>
]]
a = [==[
--[[
print("多行解释")
print("多行解释")
]]
]==]
print(type("3" + 4)) -- number
显式转换为字符串
tostring()
.. ""
恣意数字衔接一个空字符串即可转换为字符串
table
- 是对象,由自动内存接纳器举行分派和开释
- table 没有牢固大小,能够动态增加元素
{}
是 table 构造式,用来建立一个 table#
长度操纵符能够猎取 table 的大小- table 中的元素在未被初始化前都是
nil
- 能够将 table 中的元素赋值
nil
来举行删除 - 假如 table 中心部份的元素值为
nil
就申明这是一个有「闲暇」的 table - 有「闲暇」的 table 要运用
table.maxn()
来返回这个函数的最大正索引数 - table 能够用来示意模块、包、对象
- table 中的索引可所以任何值,除了
nil
- table 是匿名的
- 程序仅保存了对 table 的一个援用
- 一个唯一 table 的变量和 table 本身并没有关联
a.x
等价于a["x"]
是以字符串为索引的a[x]
是以变量x
为索引的
a = {}
for i = 1, 10 do
a[i] = i
print(a[i])
end
for i = 1, #a do
print(a[i])
end
print(a[10]) -- 10
print(#a) -- 10
a[10] = nil
print(#a) -- 9
a[10000] = 666
print(#a) -- 9
print(table.maxn(a)) -- 10000
a = {}
b = {}
c = a
print(type(a == b)) -- false
print(type(a == c)) -- true
x = "y"
a["x"] = 666
a["y"] = 777
print(a.x) --666
print(a[x]) -- 777
function
- 第一类值
- 能够存储在变量中
- 能够作为函数的返回值或参数
- lua 能够挪用本身编写的函数也能够挪用 C 言语编写的函数
- lua 规范库中的函数都是用 C 言语编写的
userdata
- 由应用程序或 C 言语编写建立的新范例
- 没有太多的预定义操纵
- 仅用来做赋值和前提测试
3. 表达式
定义
- 表达式用于示意值
- 在 lua 中,函数挪用,函数定义,数字常量、字面字符串,变量,一元和二元操纵符,table 构造式都是表达式
算数操纵符
一元操纵符
-
负号
二元操纵符
+
-
减号*
/
%
^
-- % 的技能
-- x % 1
print(3.13 % 1) -- 获得小数部份
-- x - x % 1
print(3.14 - 3.14 % 1) -- 获得整数部份
-- x - x % 0.1
print(3.14 - 3.14 % 0.1) -- 获得整数部份 + 一名小数部份
-- x - x % 0.01 以此类推,是整数部份 + 两位小数部份
关联操纵符
>
<
>=
<=
==
相称性推断~=
不等性推断
逻辑操纵符
and
第一个操纵数为假,返回第一个,不然返回第二个or
第一个操纵数为真,返回第一个,不然返回第二个not
只会返回true
或false
-- 短路操纵的运用技能
print(x = x or v) -- 初始化一个值,假如 x 为 nil 没有被初始化过,就赋值 v
-- 等价于
if not x then
x = v
end
-- 完成 C 言语中的三元操纵符, a ? b : c
print((a and b) or c) -- b 必需为真,才能够如许操纵
-- 等价于
if a == true then
return b
elseif a == false then
return c
end
-- 完成返回两个数中的较大值
max = (x > y) and x or y -- 由于 lua 将数字视为「真」
-- 等价于
if x > y then
return x
else
return y
end
字符串衔接
..
字符串衔接
优先级
1级优先
^
2级优先
-
负号not
#
3级优先
*
/
%
4级优先
+
-
减号
5级优先
..
字符串衔接
6级优先
>
<
>=
<=
==
~=
7级优先
and
8级优先
or
table 构造式
- lua 规范库中的函数对 table 的索引都是从 1 入手下手处置惩罚的
纪录作风的 table
a = {x = 10, y = 20} -- 等价于 a.x = 10, a.y = 20
夹杂运用的 table
- 这类体式格局的 table 不能以负数和操纵符作为索引
a = {
color = {"red", "green", "blue"}
width = 200,
height = 300
}
链表
- 由一系列节点构成,节点就是元素
- 节点能够再运转时动态生成
- 每一个节点包括两部份
- 存储数据的数据域
- 存储下一个地点节点的指针域
list = nil
for line in io.lines() do
list = {next = list, value = line}
end
local l = list
while l do
print(l.value)
l = l.next
end
指定索引的 table
options = {["+"] = "add", ["-"] = "sub",
["*"] = "mul", ["/"] = "div"}
print(options["+"]) -- "add"
4. 语句
- 在 lua 中包括赋值,程序构造和历程挪用
- 另有多重赋值和局部变量声明
赋值
- lua 支撑多重赋值,即
a, b = 1, 2
- 会先盘算等号右侧一切元素的值,然后再赋值
- 假如右侧的值少于左侧变量,未被初始化的变量就置为
nil
- 假如左侧变量少于右侧的值,过剩的值会被「扬弃」
- 可用来网络函数的多个返回值
- 初始化变量就是为每一个变量赋一个初始值
a, b = 1, 2
x, y = y, x -- 交流变量
a, b = 1 -- a = 1, b = nil
a, b = 1, 2, 3 -- a = 1, b = 2, 3 被扬弃
a, b = f() -- a 吸收函数 f 的第一个返回值,b 吸收第二个
a, b, c = 0, 0, 0 -- 初始化赋值
局部变量与块
块
- 一个块就是程序构造的实行体,或函数的实行体
- 在块内声明的变量仅在块内见效,即作用域为声明它们的块
- 可显式声明一个块运用
do <要实行的内容> end
将要实行的内容包裹在一个块内
局部变量
local
用来声明一个局部变量- 局部变量仅在声明它的块内见效,在块的外部无效
- 如:在轮回内部声明在的变量在轮回外部则没法运用
a = 3
b = 0
if a then
local a = 5
b = a -- 将 then 块内的局部变量 a ,保存到全局变量 b 中
print(a)
end
print(a) -- 3
print(b) -- 5
do
-- code block
end
只管运用局部变量
- 运用局部变量要比全局变量要快
- 防止污染全局环境
- 局部变量仅在声明它的块中有用,即在块外这个变量就被开释掉了
- lua 将局部变量声明看成语句处置惩罚,即能够在任何支撑誊写语句的处所誊写局部变量声明
- 声明能够包括初始化赋值
程序构造
- 程序构造中的前提表达式可所以任何值
前提构造
if
elseif
else
if 前提表达式 then
<实行体> -- 相符前提表达式实行
end
if 前提表达式1 then
<实行体 1> -- 相符前提表达式 1 实行
elseif 前提表达式2 then
<实行体 2> -- 相符前提表达式 2 实行
end
if 前提表达式 then
<实行体 1> -- 前提表达式为真时实行
else
<实行体 2> -- 前提表达式为假是实行
end
轮回构造
for
while
前提表达式为假时退出repeat ... until
前提表达式为真时推出,前提测试是在轮回体以后做的,因而轮回体最少会实行一次- 在轮回体内声明的局部变量的作用域包括了前提测试
- 轮回的三个表达式是在轮回入手下手前一次性求值的
- 掌握变量会被自动声明为 for 块中的局部变量,即作用域为 for 块,在轮回完毕后不可见
- 不要在轮回历程当中修正掌握变量的值
- 能够运用
break
或return
在轮回一般完毕前提前完毕它
for exp1, exp2, exp3 do
<轮回体>
end
while 前提表达式 do
<轮回体>
end
repeat
<轮回体>
until 前提表达式
a = 20
repeat
local a = 0
print(a)
until a == 0 -- 可接见在 repeat 块内声明的 a, 而不是全局变量 a
数值型 for
for i = 10, 0, -1 do
print(i)
end
泛型 for
ipairs()
用来遍历数组i
每次轮回时都邑给予一个新的索引值,v
则是索引值所对应的元素
a = {1, 2, 3, 4, 5, 6}
for i,v in ipairs(a) do
print(i)
print(v)
end
for i,v in pairs(a) do
print(i)
print(v)
end
两种 for 的共同点
- 轮回变量都是轮回体的局部变量
- 不应该对轮回遍历举行赋值
days = {"第一天", "第二天", "第三天"}
revdays = {}
for i, v in ipairs(days) do
revdays[v] = i -- 逆向数组,将数组索引和数组元素换取,可猎取数组元素的位置
end
print(revdays["第二天"]) -- 猎取第二天所在位置
break 和 return
break
用于完毕一个轮回,跳出内层轮回后在外层轮回中继承实行return
用于返回函数结果或简朴的完毕函数的实行- 任何函数的末端处现实都有一句隐式的
return
- 假如函数无返回值,就无需在末端处加
return
二者的共同点
- 都是用作跳出当前块
- 都须要放在一个块的末端处,即一个块的末了一条语句
- 由于
return
或break
后的语句将没法实行到 - 能够用
do ... end
块包裹return
,用与调试,即挪用函数但不实行函数内容的状况
a = 1
if a then
print("hello")
break
print("world") -- 会报错
end
for i = 1, 10 do
print(i)
if i > 3 then
break -- 只会打印 1 2 3 4 然后就跳出轮回了
end
end
-- 调试
function foo(...)
do
return
end
print("实行 foo 函数") -- 不会打印
end
foo(1, 2 ,3)
5. 函数
- 函数是对语句和表达式举行笼统的主要机制
函数的两种用法
- 一是能够完成特定的使命,一句函数挪用被视为一条语句
- 二是只用来盘算并返回特定结果,视为一句表达式
print("hello") -- 用来完成打印使命,视为一条语句
a = os.date() -- os.date() 用来返回日期,视为一句表达式
两种用法的共同点
- 都须要将一切参数放到一对圆括号中
()
- 但当参数为字面字符串或 table 构造式的时刻
()
能够省略 - 纵然挪用函数没有参数,也必需要有一对空的圆括号
()
print "hello" -- hello
print {1, 2, 3} -- 1 2 3
print(os.date) -- 当前日期
定义
function
是建立函数的关键字function add
add 是函数的称号function add(n)
n 是函数的形式参数,简称为形参add(4)
4 是挪用add()
函数时的现实参 ,简称为实参- 实参过剩形参,过剩的实参被「扬弃」
- 形参过剩实参,过剩的形参被置为
nil
function foo(a, b)
return a or b
end
foo(1) -- a = 1, b = nil
foo(1, 2) -- a = 1, b = 2
foo(1, 2, 31) -- a = 1, b = 2, 过剩的 31 被扬弃
-- 面向对象式挪用
o.foo(o, x)
o:foo(x) -- 与上面的结果一样,: 冒号操纵符,隐式的将 o 作为第一个参数
多重返回值
- lua 中的函数许可返回多个结果
- 用逗号分开所须要返回的一切参数
string.find("you are cool", "are") -- 5 7 返回找到的字符串的开头位置和末端位置
-- 查找数组中的最大元素,并返回这个元素的所在位置
function maximum(a)
local val = 1
local max = a[val]
for i,v in ipairs(a) do
if max < a[i] then
max = a[i]
val = i
end
end
return max, val
end
a = {1, 2, 55, 22, 29, 4}
maximum(a)
差别状况下的返回值
- 假如将函数作为零丁的语句实行,lua 会抛弃一切的返回值
- 假如将函数作为表达式的一部份挪用,只保存函数的第一个返回值
- 只要当函数是一系列表达式中的末了一个元素(或只要一个元素的时刻),才会猎取一切的返回值
一系列表达式的4种状况
多重赋值
- 假如一个函数挪用是末了(或唯一)的一个表达式,lua 会保存只管多的返回值,用来婚配赋值的变量
- 假如一个函数没有返回值或没有返回足够多的返回值,那末 lua 会用
nil
来补充缺失的值 - 假如一个函数挪用不是一系列表达式中的末了一个元素,就只能返回一个值
function foo() end
function foo1() return "a" end
function foo2() return "a", "b" end
-- 第一种状况,末了(或唯一)的一个表达式
x, y = foo1() -- x = a, y = b
-- 第二种状况,没有返回值
x = foo() -- nil
-- 第二种状况,没有返回足够多的返回值
x, y, z = foo1() -- x = a, y = b, z = nil
-- 第三种状况,不是表达式中的末了一个元素
x, y = foo2(), 10 -- x = a, y = 10
函数挪用时传入的实参列表
- 假如一个函数挪用作为另一个函数挪用的末了一个(或唯一的)实参的时刻,第一个函数的一切返回值都邑作为实参通报给另一个函数
function foo() end
function foo1() return "a" end
function foo2() return "a", "b" end
-- 第四种状况,作为 print 函数中的末了一个(或唯一的)实参
print(foo()) -- nil
print(foo1()) -- "a"
print(foo2()) -- "a" "b"
print(foo1() .. "test") -- "atest"
print(foo2() .. "test") -- "atest"
table 构造式
- table 构造式会完全吸收一个函数挪用的一切结果,即不会由任何数目方面的调解
- 但这类行动,只要当一个函数挪用作为末了一个元素时才发作
- 其他位置上的函数挪用老是只发生一个结果值
function foo() end
function foo1() return "a" end
function foo2() return "a", "b" end
-- 函数挪用是 table 中的末了一个元素
a = {foo2()} -- a = {"a", "b"}
a = {foo2(), 10} -- a = {"a", 10}
return 语句
- 将函数挪用放入一对圆括号 () 中,使其只返回一个结果
- return 语句背面的内容不须要 () 圆括号
- 假如强行加上则会使一个多返回值的函数,强迫其只返回一个 return(f())
function foo0() end
function foo1() return "a" end
function foo2() return "a", "b" end
function foo(i)
if i == 0 then return foo0()
elseif i == 1 then return foo1()
elseif i == 2 then return foo2()
end
end
print(foo(1)) -- a
print(foo(2)) -- a, b
print(foo(0)) -- 无返回值,在交互形式中会是一个空行
-- () 包裹
print((foo(1)) -- a
print((foo(2)) -- a
print((foo(0)) -- nil ,应该是强迫返回了一个未初始化的值,由于 foo0() 没有返回值
unpack 函数
- 吸收一个数组作为参数
- 并从下标 1 入手下手返回该数组的一切元素
- 这个预定义函数由 C 言语编写
print(unpack{10, 20, 30}) -- 10 20 30
a, b = unpack{10, 20, 30} -- a = 10, b = 20
- 用于泛型挪用
- 泛型挪用就是能够以任何实参来挪用任何函数
-- 挪用恣意函数 f, 而一切的参数都在数组 a 中
-- unpack 将返回 a 中的一切值,这些值作为 f 的实参
f(unpack(a))
f = string.find
a = {"hello", "ll"}
f(unpack(a)) -- 3 4 等效于 string.find("hello", "ll")
用 lua 递归完成 unpack
function unpack(t, i)
i = i or 1
if t[i] then
return t[i], unpack(t, i + 1)
end
end
变长参数
- lua 中的函数能够吸收差别数目的实参
- 当这个函数被挪用时,它的一切参数都邑被网络到一同
- 这部份网络起来的实参称为这个函数的「变长参数」
...
三个点示意该函数吸收差别数目的实参- 一个函数要接见它的变长参数时,须要用
...
三个点,此时...
三个点是作为一个表达式运用的 - 表达式
...
三个点的行动相似一个具有多重返回值的函数,它返回的是当前函数的一切变长参数 - 具有变长参数的函数也能够具有恣意数目的牢固参数
- 但牢固参数肯定要在变长参数之前
- 当变长参数中包括 nil ,则须要用 select 接见变长参数
- 挪用
select
时,必需传入一个牢固参数selector
(选择开关) 和一系列变长参数 - 假如
selector
为数字 n ,那末select
返回它的第 n 个可变实参 - 不然,
select
只能为字符串"#"
,如许select
会返回变长参数的总数,包括nil
-- 返回一切参数的和
function add(...)
local s = 0
for i, v in ipairs{...} do -- 表达式{...}示意一个由变长参数构成的数组
s = s + v
end
return s
end
print(add(3, 4, 5, 100)) -- 115
-- 调试技能 ,相似与直接挪用函数 foo ,但在挪用 foo 前先挪用 print 打印其一切的实参
function foo1(...)
print("calling foo:", ...)
return foo(...)
end
-- 猎取函数的实参列表
function foo(a, b, c) end
function foo(...)
local a, b, c = ...
end
-- 格式化文本 string.format ,输出文本 io.write
-- 牢固参数肯定要在变长参数之前
function fwrite(fmt, ...)
return io.write(string.format(fmt, ...))
end
fwrite() -- fmt = nil
fwrite("a") -- fmt = a
fwrite("%d%d", 4, 5) -- fmt = "%d%d" , 变长参数 = 4, 5
for i = 1, select('#', ...) do
local arg = select('#', ...)
<轮回体>
end
签字参数
- lua 中的参数通报机制是具有 「位置性」的
- 就是说在挪用一个函数时,实参是经由历程它在参数表中的位置与形参婚配起来的
- 第一个实参的值与第一个形参相婚配,依此类推
- 定义:经由历程称号来指定实参
- 可将一切的实参构造到一个 table 中,并将这个 table 作为唯一的实参传给函数
- lua 中特别的函数挪用语法,当实参只要一个 table 构造式时,函数挪用中的圆括号
()
是无足轻重的
os.rename -- 文件更名,愿望到达的结果 os.rename(old = "temp.lua", new = "temp1.lua")
-- lua 不支撑解释的写法
rename = {old = "temp.lua", new = "temp1.lua"}
function rename (arg)
return os.rename(arg.old, arg.new)
end
x = Window{x = 0, y = 0, width = 300, height = 200, title = "Lua", background = "blue", border = "true"}
-- Window 函数依据请求搜检必填参数,或为某些函数增加默认值
-- 假定 _Window 是真正用于建立新窗口的函数,请求一切参数以准确序次传入
function Window(options)
if type(options.title) ~= "string" then
error("no title")
elseif type(options.width) ~= "number" then
error("no width")
elseif type(options.height) ~= "height" then
error("no height")
end
_Window(options.title,
options.x or 0 -- 默认值
options.y or 0 -- 默认值
options.width, options.height,
options.background or "white" -- 默认值
options.border -- 默认值为 false(nil)
)
end
由于,现在只学到第五章函数篇,所以只要前五章的温习汇总,很基本,也很主要,也祝贺人人能够脚踏实地地打好地基。