lua入门笔记1 类型 表达式 语句 函数

从0开始学lua,给自己记一个笔记,使用书籍 lua程序设计(第二版),电子工业大学出版社

lua的中文API
)

此篇包含的内容有
  • 类型
  • 表达式
  • 语句
  • 函数

下面开始正式内容,有错误欢迎指出,小菜一个

1类型

  • table(表)

  1. 具有哈希结构的关联数组

  2. 可以通过除了nil外仍和类型的值来索引它,当需要创建新条目(entry)时,table会自动增长

  3. lua中主要的、仅有的数据结构机制

  4. lua中用table来表示模块(module)、包(packge)、对象(object)例如 io.read 实际是 io模块中的read函数,通过key read在io表中进行索引

  5. lua中table既不是“值”也不是“变量”而是“对象”,可以当做一种动态分配的对象,程序仅持有一个对他们的引用(||指针)lua不会暗中产生table的副本或者创建新的table

  6. table永远是匿名的anonymous,一个持有table的变量与table自身没有固定的关联性
    当一个程序再也没有对一个table的引用时,lua的垃圾收集器(garbage collector)最终会删除该table并复用他的内存

  7. 当table中的某个元素没有被初始化时,它的内容就为nil。通过将nil赋予table某个元素来删除该元素,类似于全局变量。因为lua将全局变量存储在一个普通的table中

  8. 数组通常你以1作为索引的起始值,并且有很多机制依赖于此惯例

  9. 长度操作符 # 用于返回一个数组或线性表的最后一个索引值(或为其大小 ) 如

for i=1 #a do 
  print(a[i]) 
end
  1. lua将nil作为界定数组结尾的标志,当一个数组有空隙(hole)即中间有值为nil时,长度操作符会认为这些nil元素就是结尾。如果需要处理此类数据,使用table.maxn,他会返回table的最大正索引数
  • userdata(自定义类型)

可以将任意C语言类型的数据存储到lua变量中 lua中没有太多的预定义操作 只能惊醒赋值和相等性测试

  • boolean(布尔)

true和false lua中的任何一个值都可以表示一个条件。不同于有些语言,lua中只有false和nil为假,其他任何值都为真

  • nil(空)

只有一个值,主要用于和其他任何值。一个全局变量在第一次赋值前的默认值就是nil

  • thread(线程)

具体细节之后再讲内容较多

  • funtion(函数)

  1. lua中作为第一类值来看待,函数可以存储在变量中 并可以当做参数传递,(不同于c++,函数是第二类值,只能用过指向函数地址的函数指针来传递) 可以通过参数传递给其他函数 也可以作为其他函数的返回值

  2. lua所有的标准库都是用C语言写的,标准库中包括对字符串的操作、table的操作、I/O、操作系统的功能调用、数学函数和调试函数

  • string(字符串)

  1. 不能像c一样直接修改字符串的值,每一次修改需要重新创建一个新的字符串
string a="11"; a+="2";   --错误
string a="11" a="112"   --正确
string a="11".."2"          --正确,lua中 .. 为字符串连接符
  1. 享元模式,相同字符串指向同一片内存空间

  2. 有自动内存管理机制所托管(gc)

  3. 转义字符表

转义字符: 
\a 响铃
\b 退格
\f 提供表格
\n 换行
\r 回车
\t 水平制表
\v 垂直制表
\\ 反斜杠
\" 双引号
\' 单引号
  • number(数字)

  1. 用于表示实数,lua中没有整数类型 lua中的任何数字都可以表示任何32位整数 使用双精度来表示一个 整数

  2. 可以使用科学计数法,如 0.4 4.37e6

2 表达式

  • 算术操作符

二元:
+ 加法
- 减法
* 乘法
/ 除法
^ 指数,右结合
% 取模
一元:
- 负号

--关于%运算,规则如下:
a % b == a - floor(a/b) * b
--对于实数来说:
x%1 --> x的小数部分
x-x%1 --> x的整数部分
x-x%0.01 --> x精确到小数点后两位
  • 关系操作符

>
<
<=
>=
==
~=(!=)

对于table、userdata 和函数,lua是做引用比较的。只有当他们引用同一个对象是,才认为相等
只能对于两个数字或两个字符串做大小型比较 对于 "0"与0,是不相同的

  • 逻辑操作符

and ( && )
or ( || )
not ( ! )

  1. 与条件控制语句相同,所有的逻辑操作将false和nil视为假,而其他任何东西都为真。
  2. 对于 and 和 or 来说,都是用 短路求值,也就是说他们只会在需要时哦按段第二个操作数(如and前为假,lua变不判断之后)
    常用操作:
x=x or v (若x为空赋默认值v)
max=(x>y)and x or y (返回最大值)
  • 字符串连接

  1. ".." (字符串连接符) "hello ".."world" -->"hello world"
  2. 在操作中如果任意一个操作室是数字,lua会将其转换成一个字符串
  3. lua中字符串是不可变值,连接操作只会创建 一个新的字符串
  4. 右结合
  • table构造式

  1. 用于创建和初始化table
  2. 最简单的构造式为{}空构造式,创建一个空的table
    初始化数组:
words={"a","b","c","d","e"}  printa(a[3])          --> c
a={x=10,y=20} ==> a=[]; a.x=10; a.y=20;
构造式{x=0,y=0} ==> {["x"]=0,["y"]=0}
--在一个构造式中,除了逗号还可以用分号。一般用分号用于分隔构造式中不同的成分,例如  
{x=10,y=45;"one","two","three"}

3.语句

  • 赋值

  1. 普通赋值 与c++相似差异在于多重赋值

  2. lua 中允许多重赋值,例如 a,b = 10 ,2x 赋值后,a为10,b为2x

  3. 在多重赋值中,lua先对等号右边所有元素求知,然后才执行赋值 如 x,y=y,x 交换x与y的值

  4. lua总会将有编制的个数调整到与左边变量的个数一致。 规则是 若右边值数量少,则多语的变量会被赋值为nil ;若右边值多,则多于的值会被丢弃
    注意: a,b,c=0 赋值结果为 0 nil nil

  5. 多重赋值一般用于交换两个变量或接收函数的多个返回值(lua中函数允许返回多个返回值)

  • 局部变量与块

  1. 通过local语句来创建局部变量

  2. 局部变量的作用域仅限于生命他们的那个块。一个块(block)是一个控制结构的执行体,或者是一个函数的执行体再或是一个程序块

x=10
local i =1    -- 程序块中的局部变量

while i<=x do
   local x=i*2       --while循环中的局部变量
   print(x)
end

if  i>20 then 
     local x              -- 新局变量x
     x=20               
     print(x+2)         --成功输出22,局部x
else
     print(x)              --成功输出10,全局
end

print(x)                    --输出10 全局

--如果是交互模式,可能不是此结果。
--交互模式中 每行输入的内容自身就形成了一个程序块 
--避免此情况需要使用关键字 do-end


do
     local a2=2*a
     local d=(b^2-4*a*c)^{1/2}
     x1=(-b+d)/a2
     x2=(-b-d)/a2
end                   --a2和d的作用域至此结束
print(x1,x2)
  1. 在编程中尽可能的使用局部变量,这是一种良好的编程风格 可避免一些无用的名称引入全局环境,而且访问局部变量比访问全局变量更快 切在作用域结束时,便会消失 垃圾回收器便可释放该值

  2. 在lua中有一种习惯写法时

 local foo=foo

这句代码创建了一个局部变量foo,并用全局变量foo的值初始化它,如果后续其它函数改变了全局foo的值,那么可以在这里先将他的值保存起来。这种方法还可以加速在当前作用域中对foo的访问

  1. 在需要时才声明局部变量,使得其在初始化时就拥有一个有意义的初值,并且缩短变量的作用域 这样有助于提高代码的可读性
  • 控制结构

1. 语法

if then else 
if a<0 then a=0 end
if aMAXLINES then
    showpage()
    line=0
end
-- =============================
多个嵌套 
if a==1 then 
  a=2
  elseif a==2 then 
  a=3
  else a=4
end
-- =============================
while
local i=1
while a[i] do
   print(a[i])
   i=i+1
end

repeat 一条repeat-until 语句重复执行其循环知道条件为真是结束

--打印一行不为空的内容
repeat
    local num=io.read()
until num>0                

2. for循环
2.1 数字型for

for var=exp1,exp2,exp3 do
    <执行体>
end
--表示var从exp1变化到exp2,每次以exp3为步长(默认为1)
for i=1,10 do print(i)  end       --正序输出1-10(包含10)
for i=10,1,-1,do print(i) end    --倒叙输出1-10(包含1)

不要在循环过程中修改控制变量(i)的值,跳出直接break

2.2 泛型for(foreach)

泛型for循环通过一个迭代器(iterator)函数来遍历所有值

for i ,v in ipairs(a) do print(v) end   --打印数组a的所有值

Lua基础库 提供了ipairs,这是一个用于遍历数组的迭代器函数。在每次循环中,i会被赋予一个新的索引值,同事c被赋予一个对应于该索引的数组元素值

标准库提供的几种迭代器:

io.lines --迭代文件中的每行
pairs --迭代table元素
ipairs --迭代数组元素
string.gmatch --迭代字符串中带刺

同时,也可以自行编写迭代器

3. break/return
与其他语言基本相同,不同是break与return 只能是一个举哀的最后一条语句,或者是end else until前的一条语句

4.函数

  • 基本属性

lua中函数可没有返回值(return 语句)此时返回的是nil

function testPrint()
  print "test print"
end

local t=testPrint()
  print(type(t))           -- nil

正常情况后面必须跟随圆括号,除以下特例:一个函数只有一种参数,且改参数是字面字符串或table构造式

print "hello world" ==>print("hello world") 
dofile 'a.lua' <==> dofile('a.lua')

为面向对象式的调用提供了一种特殊语法: 冒号操作符 例如:

o.foo(o,x) ==> o:foo(x) --隐含将o作为函数的第一个参数

lua中形参数量与实参数量可以不同,会自动调整数量(规则和多重赋值相同)

function f(a,b) return a or b end
f(3)a=3,b=nil
f(3,4) a=3,b=4
f(3,4,5) a=3,b=4 5被舍弃
  • 多重返回值

lua具有一项与其他语言不同的特征,允许函数返回多个结果 例如

s,e=string.find("hello lua user","lua") --如果找到返回匹配的起始字符和结尾字符的索引

编写具有多返回值的函数:

function testReturn(n)
  if n>0 then
    return 1,2
  else
    return 3
  end
end -- n>0返回1,2 否则返回3

lua会调整一个函数的返回值类型数量以适应不同的调用情况,如下。

  1. 若将函数调用作为一条单独语句时,lua会丢弃所有的返回值
  2. 若将函数作为表达式的一部分调用时,lua只保留函数的第一个返回值
  3. 当函数是一系列表达式中的最后一个元素时,才能获得 他的所有返回值(多重赋值,函数调用时传入的参数列表。table的构造式、return语句)
function foo() return 1 ,2 end
x,y=foo() --x=1 y=2
x,y=foo(),3 --x=1 y=3
  1. 当一个函数调用作为另一个函数调用的最后一个实参时,第一个函数的所有返回值豆浆作为实参传入第二个参数
print(foo()) -- 1 2
print(foo(),3) --1 3
  1. 当foo2出现在一个表达式中时,lua会将其返回值数量调整为1 如
print(foo().."x") --1x
  1. table表达式可以完整的接收一个函数调用的所有结果(只有当一个函数调用作为最后一个元素时发生)
t={foo()} --t[1]=1 t[2]=2
t={foo(),3} --t[1]=1,t[2]=3
t={0,foo()} --t[1]=0 t[2]=1 t[3]=2 
  1. 也可以将一个函数调用放入一对圆括号中,从而只返回一个结果如
print((foo())) --输出1
  1. 关于多重返回还有一个特殊函数 upack 他接受一个数组作为参数,并从1开始返回所有元素
print(unpack ({10,20,30}) ) --10 20 30
a,b=unpack(10,20,30) --a=10,b=20 30被丢弃
  1. unpack的一项重要用途体现在泛型调用(generic call) 机制中 ASNI C 中(c的标准)是无法编写泛型调用的代码 最多是声明一个可以接受长参数的函数 或者通过一个函数指针来调用不同的函数 并且无法在同一次函数调用中传入动态数量的参数,每次在调用时必须传入固定数量的参数 并且每个都要具有确定的类型 而lua中可以做到
    unpack函数等价于 return list[1],list[2].....list[j] (j=#list)
  • 变长参数

lua中的函数还可以接受不同数量的实参,例如

function Add(...)
  local s=0
  for i,v in ipairs{...} do
    s=s+v
  end
  return s
end  

print(add(3,4,10,25,12))       --> 54
  1. 参数中的3个点 (...) 表示该函数可接受不同数量的实参,一个函数要访问它的变长参数时,仍需用到三个点(...)此时这三个点是作为一个表达式来使用的 表达式{...}表示一个由所有变长参数构成的数组

  2. 表达式 "..." 的行为类似于一个具有多重返回值的函数,他返回的是当前函数的所有变长参数

  3. 具有变长参数的函数同样也可以拥有任意数量的固定参数,但固定参数必须放在变长参数之前。

  4. 在遍历一个变长参数时通常只需用到{...]如同访问一个table一样。然而如果变长参数中有我们刻意传入的nil值,则需 用到函数select,规则如下

如果 index 是个数字, 那么返回参数中第 index 个之后的部分; 负的数字会从后向前索引(-1 指最后一个参数)。 否则,index 必须是字符串 "#", 此时 select 返回参数的个数。如

for i=1,select('#',...) do 
  print(select('i',...)) 
end
  • 具名实参

类似于c/c++中具有默认值的参数 int GetAge(int age=0) 但lua中不支持这种语法,我们可以通过一些操作达到相同的效果,如下示例

function Window(options)
--检查必要参数
    if type(options.title)~="string" then error("no title") end
    if type(options.width)~=“number" then  error("no width") end
    if type(options.height)~= "number" then error("no height")  end
--其他参数都是可选的
  _Window(options.title,                        -- _Window 真正的创建窗口函数
                    options.x or 0                      --默认值
                    options.y or 0                      --默认值
                    options.width,options.height
                    options.background or "white"  --默认值
                   )
end

你可能感兴趣的:(lua入门笔记1 类型 表达式 语句 函数)