Lua笔记(24)—— tonumber和tostring

尽管Lua会提供数字和字符串之间的自动转换:

> print("10" + 30)
40
> print(10 .. 30)
1030

为了使程序的可读性更好,可以考虑使用显示转换:

> print(tonumber("10") + 30)
40
> print(tostring(10) .. tostring(30))
1030

tonumber把字符串转换为数字,而tostring则把数字转换为字符串。

另外,把数字和空字符串连接起来,也可以达到tostring的效果:

> print(type(10 .. ""))
string

 

Lua笔记(23)—— pairs和ipairs

在这篇帖子中,提到pairsipairs的区别:

pairs() returns an iterator that will return the key and value of every key in the table, in no particular order. Usually, k and v are used to hold the key and value it returns. This is used to perform actions on each item in a table in turn, like when printing the contents of each value in the table.

ipairs() is very similar to pairs(), except that it will start at table[1] and iterate through all numerically indexed entries until the first nil value. It does this in order, which can be useful when you’re looking for the first item in a list that meets certain criterion.

pairs遍历任意table,返回的keyvalue没有什么顺序。而ipairs只会返回key是数字的元素。ipairs通常用在访问数组上。

参考下面这个程序:

t = {hello = 100, 200, 300}

print("k, v in pairs:")
for k, v in pairs(t) do
    print(k, v)
end

print("k, v in ipairs:")
for k, v in ipairs(t) do
    print(k, v)
end

执行结果如下:

k, v in pairs:
1   200
2   300
hello   100
k, v in ipairs:
1   200
2   300

可以看到,pairs可以遍历所有的key-value对,而ipairs只会访问key是数字的元素。

 

Lua笔记(22)—— error和assert

Lua中的error函数定义:

error (message [, level])

打印出message后,会终止程序运行。关于level的含义,参考下面例子理解会更清楚(test.lua):

function f0()
        error("Error!")
end

function f1()
        f0()
end

function f2()
        f1()
end

f2()

执行如下:

lua: test.lua:2: Error!
stack traceback:
        [C]: in function 'error'
        test.lua:2: in function 'f0'
        test.lua:6: in function 'f1'
        test.lua:10: in function 'f2'
        test.lua:13: in main chunk
        [C]: in ?

默认情况下,level值为1。“lua: test.lua:2: Error!”把错误位置指向了脚本的第2行。把f0函数修改一下:

function f0()
        error("Error!")
end

再次执行,输出如下:

lua: test.lua:6: Error!
stack traceback:
        [C]: in function 'error'
        test.lua:2: in function 'f0'
        test.lua:6: in function 'f1'
        test.lua:10: in function 'f2'
        test.lua:13: in main chunk
        [C]: in ?

这次错误位置指向了脚本的第6行(“lua: test.lua:6: Error!”),也就是f1()函数,可以看到level指定了发生错误时,应该输出函数调用栈的哪一级函数。

assert函数定义如下:

assert (v [, message])

v是假(nilfalse)时,调用error函数,否则返回所有所有参数。其中message默认值是"assertion failed!"。举例如下:

function f0()
        assert(nil, "Assert!")
end
f0()

输出如下:

lua: test.lua:2: Assert!
stack traceback:
        [C]: in function 'assert'
        test.lua:2: in function 'f0'
        test.lua:13: in main chunk
        [C]: in ?

Lua笔记(21)—— “require module”的等价形式

Learn Lua in 15 Minutes中提到,require module的等价形式:

-- Another file can use mod.lua's functionality:
local mod = require('mod')  -- Run the file mod.lua.

-- require is the standard way to include modules.
-- require acts like:     (if not cached; see below)
local mod = (function ()
  <contents of mod.lua>
end)()
-- It's like mod.lua is a function body, so that
-- locals inside mod.lua are invisible outside it.

这个解释很好地说明了require module的原理,让人豁然开朗。

Lua笔记(20)—— 编译

loadfiledofile都会从文件中加载chunkloadfile只编译这段chunk,并且把编译好的chunk以函数的形式返回,但不运行,而dofile会运行这段chunk。此外,出现错误时,dofileraise error,而loadfile会返回错误代码dofile的代码类似这样:

function dofile (filename)
    local f = assert(loadfile(filename))
    return f()
end

load函数(Lua 5.1使用loadstring)与loadfile类似,只不过load是从字符串中加载chunk,而不是从文件中。需要注意的是,load加载的是chunk,也就是语句,不是表达式。如果要求表达式值的话,需要在前面加上return,这样就得到一个返回表达式值的语句。

Lua会把任何独立的chunk作为一个有变参参数的匿名函数的函数体。举个例子:load('a=1')返回等价于下面的表达式:

function (...) a = 1 end
 

Lua笔记(19)—— 表达式(expression)和语句(statement)

Lua中的表达式(expression)定义:

Expressions denote values. Expressions in Lua include the numeric constants and string literals, variables, unary and binary operations, and function calls. Expressions include also the unconventional function definitions and table constructors.

表达式产生值,包括:数字常量,字符串,变量,单目和双目运算,另外还有函数调用。此外,表达式还包括函数定义和创建table

Lua中的语句(statement)定义:

Lua supports an almost conventional set of statements, similar to those in C or Pascal. The conventional statements include assignment, control structures, and procedure calls. Lua also supports some not so conventional statements, such as multiple assignments and local variable declarations.

语句包括:赋值,控制结构,过程调用(block),多重赋值和local变量定义。

Lua笔记(18)—— 解释器的交互模式

Lua自带解释器(Lua.c编译生成的可执行文件)的交互模式会把每一单独的输入行看做是一个chunk,除非这一行不是完整的命令,例如:

> function test()
>> print("test")
>> end

>>标示这一行和之前的行属于同一行。

因此,如果在一行输入local i = 1Lua就会运行这个chunk。再另起一行输入新命令以后,相当于一个新的chunk,前一行的local变量是不可见的。举例如下:

> local i = 10
> print(i)
nil

解决这个问题可以使用do-end将这个代码包成一个chunk

> do
>> local i = 10
>> print(i)
>> end
10

Lua笔记(17)—— 什么是chunk?

Pil中,chunk的定义:

Each piece of code that Lua executes, such as a file or a single line in interactive mode, is called a chunk. A chunk is simply a sequence of commands (or statements).

Lua执行的一段代码,无论是一个Lua文件,或者仅仅是一条语句,均统称为chunk。说白了,chunk就是一段语句(statement)。

Lua笔记(16)——全局变量和“local”变量

执行以下Lua代码:

i = 32
local i = 0
f = load("i = i + 1; print(i)")
g = function () i = i + 1; print(i) end
f() --> 33
g() --> 1

f()输出33g()输出1。原因是第一个i是全局变量,第二个ilocal变量,而同名的local变量总是覆盖掉全局变量。load产生的函数只能看到全局变量,因此f()输出33。如果想让g()函数访问全局变量i,可以利用全局环境变量_G

g = function () _G.i = _G.i + 1; print(_G.i) end
g() --> 34

Lua笔记(15)—— “Lua Closures and Iterators”读书笔记

这篇是Lua Closures and Iterators的读书笔记:

(1)Closure有以下属性:

a) A function inside a function;
b) The inner function can see local variables of the outer function.

利用closure可以实现下列feature

a) Iterators;
b) OOP class like devices.

(2)Iterators and For Loops

代码示例:

#!/usr/bin/lua

function positive_integers(max)
    local n = 0
    return function()
        n = n + 1
        if n > max then
            return nil
        else
            return n
        end
    end
end

for v in positive_integers(3) do
    print(v)
end

Iterator含义如下:

An iterator is a function inside a function where the inner function sees the outer function's local variables. The inner function does something to increment or cycle through the local variable(s) in the outer function, returning the new value of the outer function's local variable, or something depending on that new value. The outer function passes the inner function back as a function return.

在上面例子中,iterator就是positive_integers()返回的匿名函数。

Generic for既不作用在iterator函数的返回值上,也不作用在iterator make函数上(positive_integers),而是作用在iterator函数上。