ILD

lua reference manual学习笔记2 Language
作者:YUAN JIANPENG 邮箱:yuanjp@hust.edu.cn
发布时间:2018-10-20 站点:Inside Linux Development

The Language

使用BNF语法,{}表示0次或多次,[]表示0次或1次。

3.1 Lexical Conventions

Lua是一种free-form语言。它忽略token之间的空格,换行和注释。


名字可以包含任何字母、数字和下划线,不以数字开头。名字不能为保留词汇。名字可以用用作variables, table fields, labels。


保留的keywords:

and break do else elseif end

false for function goto if in

local nil not or repeat return 

then true until while


Lua是一个大小写敏感的语言。


字符串使用单引号或双引号,可以包含类似c的转义,如\a \b \f \n \r \t \v \\ \"


行尾的反斜杠导致字符串中包括一个换行。


\z跳过空白字符包括换行,这在长字符串缩进时很有用。

1
2
3
> print("abcdfg\z
>>    sadfasdf")
abcdfgsadfasdf


任何字符可以表示成

\xXX

\ddd

XX是两个16进制数字

ddd是10进制数,注意必须有3个数字。


字符串字面量也可以表示成long format,使用long brackets包起来。

[===[

]===]

中间可以有任何个=号,=的个数叫做level。

这种形式的长字符串可以夸多行。

任何换行形式的序列被转换成一个简单的换行,如\n \r \r\n \n\r 都被转换成newline。

为了简单,如果long bracket的开头立即跟着一个换行,那么这个换行不被包含在字符串中。


数字常量可以写成一个可选的小数部分,也一个可选的10的指数,使用e或者E标识。

支持16进制常数,以0x或者0X开头。16进制支持二进制指数,使用p或者P标识。


数字包含点或者指数被当成浮点数,否则当成整数。


3 0xff 0xBEBADA

3.0

314e-2

0x0.1E    这里的E是16进制F前面的E,不是指数。

0x1p2    等价于1*(2^2)


注释以--开头,

如果--后面跟的不是long bracket,则是单行注释

如果--后面跟的是long bracket,则是多行注释,以long bracket结束

单行注释

1
-- commet


多行注释

1
2
3
4
--[[
multiple line commet
multiple line commet
]]

[[可以替换成任何level的long bracket,如[=[和]=]


3.2 Variables

Lua有3种变量

gloabl variables, local variables, table fields


单个名字表示全局变量或者局部变量(或者函数的参数,一种特殊的局部变量)。


任何变量如果没有被声明为local,都是全局变量。


变量在第一次赋值之前,其值为nil。


方括号用来索引一个表

prefixexp [ exp ]

或者

prefixexp . Name 等价于 prefixexp [ "Name" ]


访问全局变量x等价于访问_ENV.x

1
2
3
> a = 2
> print(_ENV["a"])
2


3.3 Statements

Lua支持的表达式

assignments

control structures

function calls

variable declarations


3.3.1 Blocks

块是表达式的列表,即多个表达式组成的块。


Lua使用空表达式分开表达式,分号是一个空表达式。


块以一个分号,或者两个连续的分号开始。


函数调用和赋值可以以括号开始,这可能导致歧异,如:

1
2
a = b + c
(print or io.write)('done')

可以翻译成:

1
2
a = b + c (print or io.write)('done')
a = b + c ; (print or io.write)('done')

LUA翻译成前者,为了避免这种情况,最好在每个括号前加一个分号

1
; (print or io.write)('done')



块可以显示地产生一个单个表达式来分开

1
do block end

显式块可以用来控制变量声明的作用范围,显式块也用来在另一个块的中间添加return语句。


3.3.2 Chunks

Lua编译的单元是chunk,语法上,一个chunk是一个block。


Lua处理chunk为一个匿名函数,有可变的参数。因此,一个chunk可以定义局部变量,接收参数,返回值。


3.3.3 Assignment

普通的赋值

a = 2


多个赋值

varlist = explist

list之间用逗号分开

1
2
i = 3
i, a[i] = i+1, 20

设置a[3] = 20,而不是a[4],先评估左边的。


x , y = y , x

交换x和y的值


全局变量赋值

x = val 等价于 _ENV.x = val


3.3.4 Control structures

控制结构if, while, repeat

1
2
3
while exp do block end
repeat block until exp
if exp then block {elseif exp then block } [else block] end

lua也有for语句,其有两个变种。


条件表达式可以返回任何值,false和nil被认为是false,其它值被认为是true,

(注意:数字0和空字符串也被认为是true)。


repeat-until的内部块在exp之后才结束,因此exp条件表达式可以访问内部块的局部变量。


goto语句跳到一个标签

::label::

定义一个标签

1
2
3
4
5
6
7
#!/usr/bin/env lua
 
local a = 1 
::again::
a = a + 1 
print(a)
if a < 9 then goto again end


break语句跳出while, repeat, for的循环


return语句用来从一个函数后者一个chunk返回值。

返回可以返回多个值。

return [explist] [;]


return只能写到block的最后一个statement,

如果想在中间返回,使用explicit inner block 

do return end


3.3.5 For statement

for语句有两种形式:数字和通用

1
for name '=' exp ',' exp [',' exp] do block end

第3个exp是可选的,默认为1,从第一个按第三个步进到第二个表达式。

这3个表达式只在开始的时候被评估一次。

可以使用break或者goto来退出循环。

name是loop body的局部变量,外部不可见。


第二种形式

1
for namelist in explist do block end


for var_1, ..., var_n in explist do block end


等价于:

1
2
3
4
5
6
7
8
9
do
    local f, s, var = explist
    while true do
        local var_1, ···, var_n = f(s, var)
        if var_1 == nil then break end
        var = var_1
        block
    end
end


注意:

explist只评估一次。它的结果是一个迭代函数,一个状态,一个初始值。

f, s, var是内部不可见的变量,这里只是用于解释。

可以使用break来退出循环

循环变量var_i是loop的本地变量。不能用在end之后。


3.3.6 Function Calls as Statement

函数调用可以被执行为语句

stat ::= functioncall

所有的返回值被丢弃。


3.3.7 Local Declarations

stat ::= local namelist ['=' explist]

如果explist足够多,则是multiple assignment,不够的所有的变量被初始化为nil


chunk也是一个block,所以局部变脸可以声明在一个chunk,在任何显示的block之外。


3.4 Expressions

lua中基本的表达式如下:

exp ::= prefixexp

exp ::= nil | false | true

exp ::= Numeral

exp ::= LiteralString

exp ::= functiondef

exp ::= tableconstructor

exp ::= '...'

exp ::= exp binop exp

exp ::= unop exp

prefixexp ::= var | functioncall | '(' exp ')'


3个点 ... 是vararg表达式,只能用来vararg function里面。


binary operator包括算术运算,位运算,移位运算,逻辑运算,concatenation operator


unary operator包括减、位非,逻辑非,unary length operator


函数调用和vararg expressions都可能导致multiple values,如果函数调用被用作一个表达式,它的return list被调整为zero elements,因此丢掉所有的返回值。


如果一个表达式用作为一个expressions list的最后一个(或者唯一的一个),则没有调整(除非表达式使用圆括号括起来。


所有其它情况,lua调整result list到一个元素。


f()0 results
g(f(), x)f() is adjusted to 1 result
g(x, f())g gets x plus all results from f()
a,b,c = f(), xf() is adjusted to 1 result (c get nil)
a,b = ...a获得第一个参数,b获得第二个参数
a,b,c = x, f()f() is adjusted to 2 results
a,b,c = f()f() is adjuested to 3 results
return f()returns all results from f()
return ...return all received vararg arguments
return x,y,f()return x, y and all results from f()
{f()}creates a list with all results from f()
{...}creates a list with all vararg arguments
{f(), nil}f() is adjusted to 1 result


任何使用圆括号括起来的表达式总是导致只有一个值,例如f(x,y,z)总是去第一个返回值。如果f没有返回值则为nil。


3.4.1 Arithmetic Operators

+ 加

- 减

* 乘

/ 浮点除

// floor division

% 模

^ 指数

- unary minus


如果所有的操作数是整数,则结果是整数。如果是两个操作数是数字或者可以转换为数字的字符串,则按浮点数运算。


指数和浮点除总是转算为浮点数运算。


floor division (//) 是round到负无穷的除法。


3.4.2 Bitwise operators

& | 

~ 异或

 >> <<

~ 按位取反


3.4.3 Coercions and Conversions

位操作总是把浮点数转换乘整数。

指数和浮点除总是把整数转换乘浮点数。

其它的运算符支持mixed numbers (integers and floats),会将整数转换成浮点数。

当期待一个数字时,lua会将字符串转换成数字。


3.4.4 Relational Operators

== 

~= 不等

<

>

<=

>=


== 比较它的操作数,如果类型不同,结果为false。Tables/userdata/threads比较它们的引用。


3.4.5 Logical Operators

and

or

not

所有的逻辑运算把false和nil当成false,其它任何值都当成true。


not 总是返回false或者true

and 返回它的第一个参数,如果其为false或者nil的话。否则返回第二个参数。

or 返回它的第一个参数,如果其不是nil,且不是false。否者返回第二个参数。

and or只在必要时才会评估第二个参数。


3.4.6 Concatenation

字符串连接使用两个点号 ..


3.4.7 The length Operator

长度运算是一个unary prefix operator #


字符串的长度是字符串的字节数


表的长度,是一个表的边界,如果 t[1]是nil的话,长度是0,否则border满足,t[border]不是nil,t[border+1]是nil。只有一个border的表,是一个sequence,例如table {10,20,30,40,50} 只有一个border 5。{nil, 20, 30, nil, nil, 60, nil}就有多个border。如果table不是sequence,则#可能返回任何一个border。


3.4.8 Precedence

下面从低到高的优先级

1
2
3
4
5
6
7
8
9
10
11
12
or
and
< > <= >= ~= ==
|
~
&
<< >>
..
+ -
* / // %
unary operators (not # - ~)
^


3.4.9 Table Constructors

语法

1
2
3
4
tableconstructor ::= ‘{’ [fieldlist] ‘}’
fieldlist ::= field {fieldsep field} [fieldsep]
field ::= ‘[’ exp ‘]’ ‘=’ exp | Name ‘=’ exp | exp
fieldsep ::= ‘,’ | ‘;’


大括号括起来,多个元素用都好或者分号分开。元素可以是:

[index]=value

name=value

value

3种形式。


1
a = { [f(1)] = g; "x", "y"; x = 1, f(x), [30] = 23; 45 }


等价于

1
2
3
4
5
6
7
8
9
10
11
do
local t = {}
t[f(1)] = g
t[1] = "x"        -- 1st exp
t[2] = "y"        -- 2nd exp
t.x = 1           -- t["x"] = 1
t[3] = f(x)       -- 3rd exp
t[30] = 23
t[4] = 45         -- 4th exp
a = t
end


赋值的顺序是未定义的,不要使用依赖顺序的赋值。


如果最后一个域是一个表达式,表达式是一个函数调用,或者vararg expression,则表达式返回的所有值都进入列表。


3.4.10 Function Calls

语法:

functioncall ::= prefixexp args


如果prefixexp是一个function 类型,则这个调用这个函数。否则prefixexp的call metamethod被调用。prefixexp的值作为第一个参数。跟着后面的是args指定的参数。


functioncall ::= prefixexp ‘:’ Name args

这个形式,可以用来调用method。


参数有下列语法

args ::= ‘(’ [explist] ‘)’

args ::= tableconstructor

args ::= LiteralString


所有的参数在被调用前被evaluate。


f{fileds}表调用形式等价于:f({fileds})

字符串调用形式,等价于字符串是第一个参数。


return functioncall 形式的函数调用叫做tail call。只有return 跟一个函数调用的形式才是tail call,如

return (f(x)) 不是tail call,return 2 * f(x) 也不是tail call。


3.4.11 Function Definitions

语法:

functiondef ::= function funcbody

funcbody ::= ‘(’ [parlist] ‘)’ block end


下列语法简化了函数定义:

stat ::= function funcname funcbody

stat ::= local function Name funcbody

funcname ::= Name {‘.’ Name} [‘:’ Name]


function f () body end

等价于

f = function () body end


function t.a.b.c.f () body end

等价于

t.a.b.c.f = function () body end


local function f () body end

等价于

local f; f = function () body end

而不是

local f = function () body end


变长参数使用3个点 ...

function g(a, b, ...) end


冒号用来定义method,函数有一个隐含的额外参数self

function t.a.b.c:f (params) body end

等价于

t.a.b.c.f = function (self, params) body end


3.5 Visibility Rules

Lua是一个lexically scoped language。


本地变量的scope,在声明语句之后,直到包含变量声明的innermost block的最后一个non-void statement。

1
2
3
4
5
6
7
8
9
10
11
12
x = 10                  -- global variable
do                      -- new block
    local x = x         -- new 'x', with value 10
    print(x)            --> 10
    x = x+1
    do                  -- another block
        local x = x+1
        print(x)        --> 12
    end
    print(x)            --> 11
end
print(x)                --> 10 (the global one)


注意每执行一次local 语句,都定义一个新的本地变量:

1
2
3
4
5
6
a = {}
local x = 20
for i=1,10 do
    local y = 0
    a[i] = function () y=y+1; return x+y end
end

创建10个匿名函数,每个使用不同的y变量,但是x变量相同。


Copyright © linuxdev.cc 2017-2024. Some Rights Reserved.