source code to an intermediate form before running it.
Previously, we introduced dofile as a kind of primitive operation to run chunks
of Lua code, but dofile is actually an auxiliary function: loadfile does the
hard work. Like dofile, loadfile loads a Lua chunk from a file, but it does not
run the chunk. Instead, it only compiles the chunk and returns the compiled
chunk as a function.
We could define dofile as follows:
function dofile (filename)
local f = assert(loadfile(filename))
return f()
end
Note the use of assert to raise an error if loadfile fails.
For simple tasks, dofile is handy, because it does the complete job in one call. However, loadfile is more flexible. In case of an error, loadfile returns nil plus the error message, Moreover, if we need to run a file several
times, we can call loadfile once and call its result several times. This approach is much cheaper than several
calls to dofile, because it compiles the file only once.
> f=loadfile('lession3.lua');
> f();
....excute result...
>f();--excute again.
-- write a lua with error.
> l4,errormsg=loadfile('lession4.lua'); -- notice you need anther variable to accept the error msg.
> print(l4,errormsg);
nil lession4.lua:1: syntax error near 'a'
>
The load function is similar to loadfile, except that it reads its chunk from a string, not from a file.
1In Lua 5.1, function
loadstring did this role of load.
1 For instance, consider the next line:
f = load("i = i + 1")
After this code, f will be a function that executes i=i+1 when invoked:
i = 0
f(); print(i) --> 1
f(); print(i) --> 2
The load function is powerful; we should use it with care. It is also an expensive function
load(s)() --when load finish (create a new chunk as function),directly call the function.
However, if there is any syntax error, load will return nil and the final error
message will be something like “attempt to call a nil value”. For clearer error
messages, use assert:
assert(load(s))()
Usually, it does not make sense to use load on a literal string.
f = load("i = i + 1")
f = function () i = i + 1 end
However, the second line is much faster, because Lua compiles the function
together with its enclosing chunk. In the first line, the call to load involves
a separate compilation.
summarize: load,loadString,loadfile, just create a new chunk return as a function. but dofile,will create the new chunk then excute the function as well.
--Lession4.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
Function g manipulates the local i, as expected, but f manipulates a global i,
because load always compiles its chunks in the global environment.Because load does not compile with lexical scoping,
The most typical use of load is to run external code, that is, pieces of code
that come from outside your program. For instance, you may want to plot a
function defined by the user; the user enters the function code and then you use
load to evaluate it. Note that load expects a chunk, that is, statements. If you
want to evaluate an expression, you can prefix the expression with return, so
that you get a statement that returns the value of the given expression. See the
example:
print "enter your expression:"
local l = io.read()
local func = assert(load("return " .. l))
print("the value of your expression is " .. func()) --没读一次,create a new chunk一次,
--C++ 里面加; 号expression will become a statement,but Lua, ; 是可有可无的,need to add return to become a statement.
--see my example:
customerCode=[==[
i=5;
i=i+1;
print(i);
function myTestFunction()
local i=10;
print(i);
end
myTestFunction();
]==];
--print(customerCode);
local myFunc=load(customerCode); --一次性执行,,,
myFunc();
--这下需要搞清楚statement and expression
in C++ primer, I got the definition: P148 ,and P191
An expression is composed of one or more operands that are combined by operators. the simplest form consists of a single literal constant or a vaariable, Note every expression yieds a result. check below case:
if(ival) //即使是single variable also will yied result, not zero is true, fails otherwise. but in Lua. only false / nil is evaluate as fasle,others eventhoug is 0, also is true.
Statement : are analogous to sentences in a natural language. In C++ there are simple statements that excutes a single task and compund statement that excute as a unit like for, if,while,do while satement.
in C++,most statements end with a semicolon, 这也解析了why in the class declare statement, we need to end with
semicolon. class MyStudent {}; // remember this semicolon.
as expression.such as ival+5, become as expression statement by following it with a semicolon;
; //just a semicolon is a null statement,
ival=v1+v2;; //ok.
Declaration statments: define or declare an object or class.
Compound statment :blocl ,like while,if...
--------------------------------
lession5.lua
a=5;
b=11;
c=a+b;
print(c);
local function Mytesfunc(a,b)
local c=a+b;
print("call function my:" ..c);
end
Mytesfunc(1,2);
------------------------------------
lession6.lua
for l in io.lines("lession5.lua") do
print(l); --逐行print out
end
for l in io.lines("lession5.lua","*L") do
print(l); --不知道为什么加*L 虽然也是逐行print out但会多一些空行
end
for l in io.lines("lession5.lua",1024) do
print(l); -1024 ,一次性print out 出来了
end
print("test end....");
fk=load(io.lines("lession5.lua","*L"));
fk();
fk=load(io.lines("lession5.lua","1024")); -- more faster.because it will return once when call io.lines with 1024 space.
fk();
-- but with io.lines("lession5.lua","*L") will return one line by line with some blank space , 因为load 也call 返回io.lines
返回的iterator function. when this iterator function return nill, then will end the reading. then will starting to create a new chunck.
Lua treats any independent chunk as the body of an anonymous function with a variable number of arguments.
For instance, load("a = 1") returns the equivalent of the following expression:
function (...) a = 1 end
Like any other function, chunks can declare local variables:
f = load("local a = 10; print(a + 20)")
f() --> 30
The load functions never raise errors. In case of any kind of error, they return nil plus an error message:
print(load("i i"))
--> nil [string "i i"]:1: '=' expected near 'i' --也就是程序的执行不会中断。。。
-- file 'foo.lua'
function foo (x)
print(x)
end
We then run the command
f = loadfile("foo.lua")
After this command, foo is compiled, but it is not defined yet. To define it, you must run the chunk:
print(foo) --> nil -- foo 此时还是不存在的
f() -- defines 'foo' ,当执行了这个loaded chunk 后 foo 才存在
foo("ok") --> ok
8.2 Precompiled Code
The simplest way to produce a precompiled file—also called a binary chunk in Lua jargon—is with the luac program
$ luac -o prog.lc prog.lua --compile
$ lua prog.lc -- excute
p=loadfile("lession5.lua"); --loadfile will compile lession5.lua, we use string.dump, 把compile 的结果dump 出来
f=io.open("lession5.lc","wb");
f:write(string.dump(p)); --然后io write to a new binary file.
f:close();
The key function here is string.dump: it receives a Lua function and returns its
precompiled code as a string, properly formatted to be loaded back by Lua.
C:\Trevor\lua\bin>luac -l -o lession6.lc lession6.lua
main <lession6.lua:0,0> (66 instructions at 004B2230)
0+ params, 7 slots, 1 upvalue, 15 locals, 19 constants, 0 functions
1 [1] GETTABUP 0 0 -1 ; _ENV "io"
2 [1] GETTABLE 0 0 -2 ; "lines"
3 [1] LOADK 1 -3 ; "lession5.lua"
4 [1] CALL 0 2 4
5 [1] JMP 0 3 ; to 9
6 [2] GETTABUP 5 0 -4 ; _ENV "print"
7 [2] MOVE 6 3
8 [2] CALL 5 2 1
option -l lists the opcodes that the compiler generates for a given chunk.
Code in precompiled form is not always smaller than the original, but it loads faster.
Besides its required first argument, load has three more arguments, all of
them optional. The second is a name for the chunk, which is used only in error
messages. The fourth argument is an environment, which we will discuss in
Chapter 14. The third argument is the one we are interested here; it controls
what kinds of chunks can be loaded. If present, this argument must be a
string: the string “t” allows only textual (normal) chunks; “b” allows only binary
(precompiled) chunks; “bt”, the default, allows both formats.
8.3 C Code
Normally, Lua does not include facilities that cannot be implemented in
ANSI C. However, dynamic linking is different. in this particular case, Lua breaks its portability rules and implements a dynamic linking facility for several platforms.
Lua provides all the functionality of dynamic linking through a single function, called package.loadlib. It has two string arguments: the complete path of a library and the name of a function in
that library. So, a typical call to it looks
like the next fragment
local path = "/usr/local/lib/lua/5.1/socket.so"
local f = package.loadlib(path, "luaopen_socket")
The loadlib function loads the given library and links Lua to it. However, it does not call the given function. Instead, itreturns the C function as a Lua function. If there is any error
loading the library or finding the initialization
function, loadlib returns nil plus an error message.
More often than not, we load C libraries using require. This function searches for the library and uses loadlib
to load an initialization function for the library. When called, this initialization
function builds and returns a table with the functions from that library, much
as a typical Lua library does. We will discuss require in Section 15.1, and more
details about C libraries in Section 27.3.
8.4 Errors
Errare humanum est
You can also explicitly raise an error calling the error function with an error message as an
argument. Usually, this function is the appropriate way to signal errors in your
code:
print "enter a number:"
n = io.read("*n")
if not n then error("invalid input") end
This construction of calling error subject to some condition is so common that
Lua has a built-in function just for this job, called assert:
print "enter a number:"
n = assert(io.read("*n"), "invalid input")
The assert function checks whether its first argument is not false and simply returns this argument; if the argument is false, assert raises an error. Its second argument, the message, is optional. Beware, however, that assert is a regular function. As such, Lua always evaluates its arguments before calling
the function. Therefore, if you have something like
n = io.read()
assert(tonumber(n), "invalid input: " .. n .. " is not a number")
Lua will always do the concatenation, even when n is a number. It may be wiser
to use an explicit test in such cases.
When a function finds an unexpected situation (an exception), it can assume two basic behaviors: it can return an error code (typically nil) or it can raise an error, calling function error. There are no fixed rules for choosing between these two options, but we can provide a general guideline:
an exception that is easily avoided should raise an error; otherwise, it should return an error code.
local res = math.sin(x)
if not res then -- error? --其实没办法执行到这一步,因为已经抛到main ,由applicaion 自己处理了
<error-handling code>
However, we could as easily check this exception before calling the function:
if not tonumber(x) then -- x is not a number? --this is the best way
<error-handling code>
local file, msg
repeat
print "enter a file name:"
local name = io.read()
if not name then return end -- no input
file, msg = io.open(name, "r") --自己会返回一个error msg.
if not file then print(msg) end
until file
file = assert(io.open(name, "r"))
This is a typical Lua idiom: if io.open fails, assert will raise an error.
file = assert(io.open("no-file", "r")) --其实就是io.open 返回了两个结果pass to assert function.if the first is nil,then raise an error with the second error msg result.
--> stdin:1: no-file: No such file or directory
8.5 Error Handling and Exceptions
For many applications, you do not need to do any error handling in Lua; 就像math.sin, 如果传入字符串,直接抛到applicaion main 这一层,我们都没法捕获 (办法在下面 :pcall) the application program does this handling.
However, if you need to handle errors in Lua, you must use the pcall (protected
call) function to encapsulate your code.
local ok, msg = pcall(function ()
<some code>
if unexpected_condition then error() end
<some code>
print(a[i]) -- potential error: 'a' may not be a table
<some code>
end)
----
local ok,msg=pcall(
function () --注意一定要用function 包裹要call的funciton.
return math.sin('abc') --notic ,you need to return, orelse ,if no error happen, can not get the sin result.
end
);
print(ok, msg); --
i=0;
i=i+1;
print(i); --可以看到用了pcall后,哪怕math.sin 抛出了error,都可以被捕获到,,是可以执行到这里的不会被中断,,
If there are no errors, pcall
returns true, plus any values returned by the call. Otherwise, it returns false,
plus the error message.
local status, err = pcall(function () error({code=121}) end)
print(err.code) --> 121
These mechanisms provide all we need to do exception handling in Lua. We
throw an exception with error and catch it with pcall. The error message
identifies the kind of error.
local k,m=pcall(
function ()
error({code=120,message='theris an error msg'}); --其实这个table 可以自己定义,,code or errrcode,自己喜欢了
end
);
print(m.code,m.message);
8.6 Error Messages and Tracebacks
When there is an internal error (such as an attempt to index a non-table value), Lua generates the error
message; otherwise, the error message is the value passed to the error function.
Whenever the message is a string, Lua tries to add some information about the location where the error happened:
local status, err = pcall(function () a = "a"+1 end)
print(err)
--> stdin:1: attempt to perform arithmetic on a string value
local status, err = pcall(function () error("my error") end)
print(err)
--> stdin:1: my error
The location information gives the file name (stdin, in the example) plus the line number (1, in the example).
The error function has an additional second parameter, which gives the level where it should report the error; you use this parameter to blame someone else for the error. For instance, suppose you write a function whose first task is to check whether it was called correctly:
function foo(str)
if type(str) ~='string' then
error("hey,please iput a string",1);--with leve 1.
end
print('you input is :'..str);
end
foo(1234);
---
lession6.lua:47: hey,please iput a string --47 行就是 call error function 的那行
stack traceback:
[C]: in function 'error'
lession6.lua:47: in function 'foo'
lession6.lua:51: in main chunk
[C]: in function 'dofile'
stdin:1: in main chunk
[C]: in ?
---------
lession6.lua:51: hey,please iput a string --51 行是 call foo(1234) 的那一行,,
stack traceback:
[C]: in function 'error'
lession6.lua:47: in function 'foo'
lession6.lua:51: in main chunk
[C]: in function 'dofile'
stdin:1: in main chunk
[C]: in ?
-----------
When pcall returns its error message, it destroys part of the stack (the part that goes from it to the error point). Consequently, if we want a traceback, we must build it before pcall returns. To do this, Lua provides the xpcall function. Besides the function to be called, it receives a second argument, a message handler function. In case
of an error, Lua calls this message handler before the stack unwinds, so that it can use the debug library to gather any extra information it wants about the error. Two common message handlers are debug.debug, which gives you a Lua prompt so that you can inspect by yourself what was going on when the error happened; and debug.traceback, which builds an extended error message with
a traceback.3 The latter is the function that the stand-alone interpreter uses to
build its error messages.
local ok,msg=xpcall(function ()
foo(1234)
end
,debug.debug);
--will continue this part at chapter 24