当前位置: 首页 > news >正文

跟着 Lua 5.1 官方参考文档学习 Lua (2)

文章目录

    • 2.3 – Variables
    • 2.4 – Statements
      • 2.4.1 – Chunks
      • 2.4.2 – Blocks
      • 2.4.3 – Assignment
      • 2.4.4 – Control Structures
      • 2.4.5 – For Statement
      • 2.4.6 – Function Calls as Statements
      • 2.4.7 – Local Declarations

2.3 – Variables

Variables are places that store values. There are three kinds of variables in Lua: global variables, local variables, and table fields.

A single name can denote a global variable or a local variable (or a function’s formal parameter, which is a particular kind of local variable):

	var ::= Name

Name denotes identifiers, as defined in §2.1.

Any variable is assumed to be global unless explicitly declared as a local (see §2.4.7). Local variables are lexically scoped: local variables can be freely accessed by functions defined inside their scope (see §2.6).

Before the first assignment to a variable, its value is nil.

Square brackets are used to index a table:

	var ::= prefixexp `[´ exp `]´

The meaning of accesses to global variables and table fields can be changed via metatables. An access to an indexed variable t[i] is equivalent to a call gettable_event(t,i). (See §2.8 for a complete description of the gettable_event function. This function is not defined or callable in Lua. We use it here only for explanatory purposes.)

The syntax var.Name is just syntactic sugar for var["Name"]:

	var ::= prefixexp `.´ Name

All global variables live as fields in ordinary Lua tables, called environment tables or simply environments (see §2.9). Each function has its own reference to an environment, so that all global variables in this function will refer to this environment table. When a function is created, it inherits the environment from the function that created it. To get the environment table of a Lua function, you call getfenv. To replace it, you call setfenv. (You can only manipulate the environment of C functions through the debug library; (see §5.9).)

例子:修改 Lua 函数的环境

x = 10

function foo()
    print("x= ", x)
end

foo()

-- 修改Lua函数的环境
local new_env = {x = 20, print = print}
setfenv(foo, new_env)

foo()

输出

x=      10
x=      20

An access to a global variable x is equivalent to _env.x, which in turn is equivalent to

     gettable_event(_env, "x")

where _env is the environment of the running function. (See §2.8 for a complete description of the gettable_event function. This function is not defined or callable in Lua. Similarly, the _env variable is not defined in Lua. We use them here only for explanatory purposes.)

gettable_event 函数

     function gettable_event (table, key)
       local h
       if type(table) == "table" then
         local v = rawget(table, key)
         if v ~= nil then return v end
         h = metatable(table).__index
         if h == nil then return nil end
       else
         h = metatable(table).__index
         if h == nil then
           error(···)
         end
       end
       if type(h) == "function" then
         return (h(table, key))     -- call the handler
       else return h[key]           -- or repeat operation on it
       end
     end

2.4 – Statements

Lua supports an almost conventional set of statements, similar to those in Pascal or C. This set includes assignments, control structures, function calls, and variable declarations.

2.4.1 – Chunks

The unit of execution of Lua is called a chunk. A chunk is simply a sequence of statements, which are executed sequentially. Each statement can be optionally followed by a semicolon:

	chunk ::= {stat [`;´]}

There are no empty statements and thus ‘;;’ is not legal.

例子:4 个等价的 chunk

a = 1
b = a*2

a = 1;
b = a*2;

a = 1; b = a*2

a = 1 b = a*2 -- ugly, but valid

Lua handles a chunk as the body of an anonymous function with a variable number of arguments (see §2.5.9). As such, chunks can define local variables, receive arguments, and return values.

A chunk can be stored in a file or in a string inside the host program. To execute a chunk, Lua first pre-compiles the chunk into instructions for a virtual machine, and then it executes the compiled code with an interpreter for the virtual machine.

例子:使用 C API 给 Lua chunk 传递参数,获取返回值

#include <stdio.h>
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>

int main() {
    lua_State *L = luaL_newstate();  // 创建一个新的 Lua 状态
    luaL_openlibs(L);  // 打开 Lua 标准库

    // chunk 代码
    const char *chunk = 
        "local s = 0\n"
        "for i, v in ipairs{...} do\n"
        "   s = s + v\n"
        "end\n"
        "return s\n";

    // 加载 chunk
    if (luaL_loadstring(L, chunk) != 0) {
        printf("load error!\n");
        return 1;
    }

    // 给 chunk 传递参数
    lua_pushnumber(L, 1);
    lua_pushnumber(L, 2);
    lua_pushnumber(L, 3);

    // 执行 chunk。3个参数,1个返回值
    lua_call(L, 3, 1);

    // 检查返回值
    if (lua_isnumber(L, -1)) {
        double x = lua_tonumber(L, -1);
        printf("result= %f\n", x);  // 输出结果
    }

    lua_pop(L, 1);  // 弹出返回值

    lua_close(L);  // 关闭 Lua 状态
    return 0;
}

例子:Lua 中给 chunk 传递参数,获取返回值

-- chunk 代码
local chunk = [[
local s = 0
for i, v in ipairs{...} do
s = s + v
end
return s
]]

-- 加载 chunk
local f, err = loadstring(chunk)
if err then
    error(err)
end

-- 执行 chunk。3个参数,1个返回值
local success, res = pcall(f, 1, 2, 3)
if not success then
    print("pcall error: ", res)
else
    print("res= ", res)
end

补充:

Lua treats any independent chunk as the body of an anonymous function with a variable number of arguments. For instance, loadstring(“a = 1”) returns the equivalent of the following expression:

function (...) a = 1 end

Like any other function, chunks can declare local variables:

f = loadstring("local a = 10; print(a + 20)")
f() --> 30

Chunks can also be pre-compiled into binary form; see program luac for details. Programs in source and compiled forms are interchangeable; Lua automatically detects the file type and acts accordingly.

2.4.2 – Blocks

A block is a list of statements; syntactically, a block is the same as a chunk:

	block ::= chunk

A block can be explicitly delimited to produce a single statement:

	stat ::= do block end

Explicit blocks are useful to control the scope of variable declarations. Explicit blocks are also sometimes used to add a return or break statement in the middle of another block (see §2.4.4).

2.4.3 – Assignment

Lua allows multiple assignments. Therefore, the syntax for assignment defines a list of variables on the left side and a list of expressions on the right side. The elements in both lists are separated by commas:

	stat ::= varlist `=´ explist
	varlist ::= var {`,´ var}
	explist ::= exp {`,´ exp}

Expressions are discussed in §2.5.

Before the assignment, the list of values is adjusted to the length of the list of variables. If there are more values than needed, the excess values are thrown away. If there are fewer values than needed, the list is extended with as many nil’s as needed.

例子:赋值语句

local a, b = 1, 2, 3
print(a, b)

local c, d, e = 1, 2
print(c, d, e)

输出

1       2
1       2       nil

If the list of expressions ends with a function call, then all values returned by that call enter the list of values, before the adjustment (except when the call is enclosed in parentheses; see §2.5).

例子:最后一个表达式是函数调用

function foo()
    return 1, 2, 3
end

local a, b, c = 1, foo()
print(a, b, c)

local d, e, f = 1, 2, (foo())
print(d, e, f)

输出

1       1       2
1       2       1

The assignment statement first evaluates all its expressions and only then are the assignments performed. Thus the code

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

sets a[3] to 20, without affecting a[4] because the i in a[i] is evaluated (to 3) before it is assigned 4. Similarly, the line

     x, y = y, x

exchanges the values of x and y, and

     x, y, z = y, z, x

cyclically permutes the values of x, y, and z.

例子:赋值语句

a = {}
i = 3
i, a[i] = i+1, 20
print("i=", i)
print("a[3]=", a[3])
print("a[4]=", a[4])

x, y, z = 1, 2, 3
x, y, z = y, z, x
print(x, y, z)

输出

i=      4
a[3]=   20
a[4]=   nil
2       3       1

解释

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

因为先求值,所以a[i]中的i表达式求值为3,右边的表达式求值为4,20。赋值后i变成4,a[3]变成20。

The meaning of assignments to global variables and table fields can be changed via metatables. An assignment to an indexed variable t[i] = val is equivalent to settable_event(t,i,val). (See §2.8 for a complete description of the settable_event function. This function is not defined or callable in Lua. We use it here only for explanatory purposes.)

An assignment to a global variable x = val is equivalent to the assignment _env.x = val, which in turn is equivalent to

     settable_event(_env, "x", val)

where _env is the environment of the running function. (The _env variable is not defined in Lua. We use it here only for explanatory purposes.)

settable_event 函数

     function settable_event (table, key, value)
       local h
       if type(table) == "table" then
         local v = rawget(table, key)
         if v ~= nil then rawset(table, key, value); return end
         h = metatable(table).__newindex
         if h == nil then rawset(table, key, value); return end
       else
         h = metatable(table).__newindex
         if h == nil then
           error(···)
         end
       end
       if type(h) == "function" then
         h(table, key,value)           -- call the handler
       else h[key] = value             -- or repeat operation on it
       end
     end

2.4.4 – Control Structures

The control structures if, while, and repeat have the usual meaning and familiar syntax:

	stat ::= while exp do block end
	stat ::= repeat block until exp
	stat ::= if exp then block {elseif exp then block} [else block] end

Lua also has a for statement, in two flavors (see §2.4.5).

The condition expression of a control structure can return any value. Both false and nil are considered false. All values different from nil and false are considered true (in particular, the number 0 and the empty string are also true).

In the repeatuntil loop, the inner block does not end at the until keyword, but only after the condition. So, the condition can refer to local variables declared inside the loop block.

例子:repeat-until 循环

local x = 9
local sqr = x/2
repeat
    sqr = (sqr + x/sqr)/2
    local error = math.abs(sqr^2 - x)
until error < x/10000 -- ’error’ still visible here

print("sqr=", sqr)

The return statement is used to return values from a function or a chunk (which is just a function). Functions and chunks can return more than one value, and so the syntax for the return statement is

	stat ::= return [explist]

The break statement is used to terminate the execution of a while, repeat, or for loop, skipping to the next statement after the loop:

	stat ::= break

A break ends the innermost enclosing loop.

The return and break statements can only be written as the last statement of a block. If it is really necessary to return or break in the middle of a block, then an explicit inner block can be used, as in the idioms do return end and do break end, because now return and break are the last statements in their (inner) blocks.

例子:return 语句在 block 中间

function foo()
    do return end -- return 语句不是末尾会报错,需要改成 do return end
    local a = 1
    print("a")
end

foo()

2.4.5 – For Statement

The for statement has two forms: one numeric and one generic.

The numeric for loop repeats a block of code while a control variable runs through an arithmetic progression. It has the following syntax:

	stat ::= for Name `=´ exp `,´ exp [`,´ exp] do block end

The block is repeated for name starting at the value of the first exp, until it passes the second exp by steps of the third exp. More precisely, a for statement like

     for v = e1, e2, e3 do block end

is equivalent to the code:

     do
       local var, limit, step = tonumber(e1), tonumber(e2), tonumber(e3)
       if not (var and limit and step) then error() end
       while (step > 0 and var <= limit) or (step <= 0 and var >= limit) do
         local v = var
         block
         var = var + step
       end
     end

Note the following:

  • All three control expressions are evaluated only once, before the loop starts. They must all result in numbers.
  • *var*, *limit*, and *step* are invisible variables. The names shown here are for explanatory purposes only.
  • If the third expression (the step) is absent, then a step of 1 is used.
  • You can use break to exit a for loop.
  • The loop variable v is local to the loop; you cannot use its value after the for ends or is broken. If you need this value, assign it to another variable before breaking or exiting the loop.

例子:第一种形式的 for 循环

for i = 1, 10, 2 do
    print(i) -- 1 3 5 7 9
end

for i = 5, 1, -1 do
    print(i) -- 5 4 3 2 1
end

The generic for statement works over functions, called iterators. On each iteration, the iterator function is called to produce a new value, stopping when this new value is nil. The generic for loop has the following syntax:

	stat ::= for namelist in explist do block end
	namelist ::= Name {`,´ Name}

A for statement like

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

is equivalent to the code:

     do
       local f, s, var = explist
       while true do
         local var_1, ···, var_n = f(s, var)
         var = var_1
         if var == nil then break end
         block
       end
     end

Note the following:

  • *explist* is evaluated only once. Its results are an iterator function, a state, and an initial value for the first iterator variable.
  • *f*, *s*, and *var* are invisible variables. The names are here for explanatory purposes only.
  • You can use break to exit a for loop.
  • The loop variables *var_i* are local to the loop; you cannot use their values after the for ends. If you need these values, then assign them to other variables before breaking or exiting the loop.

补充:Despite its apparent simplicity, the generic for is powerful. With proper iterators, we can traverse almost anything in a readable fashion. The standard libraries provide several iterators, which allow us to iterate over the lines of a file (io.lines), the pairs of a table (pairs), the entries of an array (ipairs), the words of a string (string.gmatch), and so on. Of course, we can write our own
iterators.

例子:第二种形式的 for 循环,实现 ipairs 和 pair 函数

local function iter(a, i)
    i = i + 1
    local v = a[i]
    if v then
        return i, v
    end
end

function ipairs(a)
    return iter, a, 0
end

local a = {"a", "b", "c" ,"d"}
for i,v in ipairs(a) do
    print(i, v)
end

function pairs(t)
    return next, t, nil
end

local t = {a = 1, b = 2, c = 3}
for k,v in pairs(t) do
    print(k, v)
end

2.4.6 – Function Calls as Statements

To allow possible side-effects, function calls can be executed as statements:

	stat ::= functioncall

In this case, all returned values are thrown away. Function calls are explained in §2.5.8.

函数调用作为一条语句,所有的返回值会被丢弃。

2.4.7 – Local Declarations

Local variables can be declared anywhere inside a block. The declaration can include an initial assignment:

	stat ::= local namelist [`=´ explist]

If present, an initial assignment has the same semantics of a multiple assignment (see §2.4.3). Otherwise, all variables are initialized with nil.

A chunk is also a block (see §2.4.1), and so local variables can be declared in a chunk outside any explicit block. The scope of such local variables extends until the end of the chunk.

The visibility rules for local variables are explained in §2.6.

相关文章:

  • 【HarmonyOS NEXT】获取正式应用签名证书的签名信息
  • 基于 Spring Boot + 微信小程序的短文写作竞赛管理系统设计与实现(源码+文档)
  • 《Python在数据可视化中的应用与实践》
  • 在nodejs中使用ElasticSearch(一)安装,使用
  • css主题色修改后会多出一个css吗?css怎么定义变量?
  • C++ day2
  • JVM深入理解
  • 网络安全技术pat实验 网络安全 实验
  • floodfill算法系列一>衣橱整理
  • GPT-SoVITS更新V3 win整合包
  • iOS进程增加内存上限的接口
  • C#发送邮件
  • 为什么Agent会失败?2025年对AI的预测
  • 网络安全中的机器学习
  • Java 反射
  • docker 部署JAR
  • ES10中Object.fromEntries(),trimStart() ,trimend()的使用方法和使用场景例子
  • 三、linux字符驱动详解
  • 算法——位运算
  • 零基础学QT、C++(三)魔改QT组件库(付源码)
  • 江西望仙谷回应“游客凌晨等不到接驳车”:已限流,接驳车运行时间延长
  • 华尔兹转岗与鲁比奥集权:特朗普政府人事震荡背后的深层危机
  • 对谈|“对工作说不”是不接地气吗?
  • 生命与大海相连:他在300多米的深海行走,在沉船一线打捞救援
  • 党政机关停车场免费、食堂开放,多地“五一”游客服务暖心周到
  • 刘洪洁已任六安市委副书记、市政府党组书记