Lua 2 Types and Values

There are eight basic types in Lua:

nil, boolean, number, string, userdata, function, thread, and table

print(type("Hello world"))  --> string
print(type(10.4 * 3))       --> number
print(type(print))          --> function
print(type(type))           --> function
print(type(true))           --> boolean
print(type(nil))            --> nil
print(type(type(X)))        --> string

nil

Nil is a type with a single value, nil, whose main property is to be different from
any other value. Lua uses nil as a kind of non-value, to represent the absence
of a useful value. As we have seen, a global variable has a nil value by default,
before its first assignment, and you can assign nil to a global variable to delete
it.

boolean

The boolean type has two values,false and true, which represent the traditional
boolean values. However, booleans do not hold a monopoly of condition values:
in Lua, any value can represent a condition. Conditional tests (e.g., conditions in
control structures) consider both the boolean false and nil as false and anything
else as true. In particular, Lua considers both zero and the empty string as true
in conditional tests.
Throughout this book, I will type “false” to mean any false value, that is, the
boolean false or nil. When I mean specifically the boolean value, I will type
“false”. The same holds for “true” and “true”.

number

The number type represents real (double-precision floating-point) numbers. Lua
has no integer type.
Some people fear that even a simple increment or comparison can go weird
with floating-point numbers. Reality, however, is not like that. Virtually all plat-
forms nowadays follow the IEEE 754 standard for floating-point representation.
Following this standard, the only possible source of errors is a representation er-
ror, which happens when a number cannot be exactly represented. An operation
rounds its result only if that result has no exact representation. Any operation
with a result that has an exact representation must give that exact result.
The fact is that any integer up to 2 53 (approximately 10 16 ) has an exact
representation as a double-precision floating-point number. When you use a
double to represent an integer, there is no rounding error at all, unless the2.4
number has an absolute value greater than 2 53 . In particular, a Lua number
can represent any 32-bit integer without rounding problems.
Of course, fractional numbers can have representation errors. The situation
here is not different from what happens with pen and paper. If we want to
write 1/7 in decimal, we will have to stop somewhere. If we use ten digits
to represent a number, 1/7 becomes rounded to 0.142857142. If we compute
1/7 * 7 using ten digits, the result will be 0.999999994, which is different from 1.
Moreover, numbers that have a finite representation in decimal can have an
infinite representation in binary. For instance, 12.7 - 20 + 7.3 is not exactly zero
when computed with doubles, because both 12.7 and 7.3 do not have an exact
finite representation in binary (see Exercise 2.3).
Before we go on, remember: integers do have exact representations and
therefore do not have rounding errors.
Most modern CPUs do floating-point arithmetic as fast as (or even faster
than) integer arithmetic. Nevertheless, it is easy to compile Lua so that it
uses another type for numbers, such as longs or single-precision floats. This
is particularly useful for platforms without hardware support for floating point,
such as embedded systems. See file luaconf.h in the distribution for details.
We can write numeric constants with an optional decimal part, plus an
optional decimal exponent. Examples of valid numeric constants are:
4
0.4
4.57e-3
0.3e12
5E+20
Moreover, we can also write hexadecimal constants, prefixing them with 0x .
Since Lua 5.2, hexadecimal constants can also have a fractional part and a
binary exponent (prefixed by ‘ p ’ or ‘ P ’), as in the following examples:
0xff (255)
0x1A3 (419)
0x0.2 (0.125)
0x1p-1 (0.5)
0xa.bp2 (42.75)
(For each constant, we added its decimal representation in parentheses.)

string

Strings in Lua have the usual meaning: a sequence of characters. Lua is
eight-bit clean and its strings can contain characters with any numeric code,
including embedded zeros. This means that you can store any binary data into
a string. You can also store Unicode strings in any representation (UTF-8, UTF-
16, etc.). The standard string library that comes with Lua offers no explicit
support for those representations. Nevertheless, we can handle UTF-8 strings
quite reasonably, as we will discuss in Section 21.7.
Strings in Lua are immutable values. You cannot change a character inside
a string, as you can in C; instead, you create a new string with the desired
modifications, as in the next example:
a = “one string”
b = string.gsub(a, “one”, “another”) – change string parts
print(a)
–> one string
print(b)
–> another string
Strings in Lua are subject to automatic memory management, like all other
Lua objects (tables, functions, etc.). This means that you do not have to worry
about allocation and deallocation of strings; Lua handles this for you. A string
can contain a single letter or an entire book. Programs that manipulate strings
with 100K or 1M characters are not unusual in Lua.
You can get the length of a string using the prefix operator ‘ # ’ (called the
length operator):
a = “hello”
print(#a)
print(#”good\0bye”)
–> 5
–> 8
Literal strings
We can delimit literal strings by matching single or double quotes:
a = “a line”
b = ‘another line’
They are equivalent; the only difference is that inside each kind of quote you can
use the other quote without escapes.
As a matter of style, most programmers always use the same kind of quotes
for the same kind of strings, where the “kinds” of strings depend on the program.
For instance, a library that manipulates XML may reserve single-quoted strings
for XML fragments, because those fragments often contain double quotes.
Strings in Lua can contain the following C-like escape sequences:
\a
\b
\f
\n
\r
\t
\v
\
\”
\’
bell
back space
form feed
newline
carriage return
horizontal tab
vertical tab
backslash
double quote
single quote
The following examples illustrate their use:

print(“one line\nnext line\n\”in quotes\”, ‘in quotes’”)
one line
next line
“in quotes”, ‘in quotes’
print(‘a backslash inside quotes: \’\\”)
a backslash inside quotes: ‘\’
print(“a simpler way: ‘\’”)
a simpler way: ‘\’

We can specify a character in a string also by its numeric value through the
escape sequences \ ddd and \x\ hh, where ddd is a sequence of up to three dec-
imal digits and hh is a sequence of exactly two hexadecimal digits. As a some-
what complex example, the two literals “alo\n123\”” and ‘\97lo\10\04923”’
have the same value, in a system using ASCII: 97 is the ASCII code for ‘ a ’, 10 is
the code for newline, and 49 is the code for the digit ‘ 1 ’. (In this example we must
write 49 with three digits, as \049 , because it is followed by another digit; other-
wise Lua would read the number as 492.) We can also write that same string as
‘\x61\x6c\x6f\x0a\x31\x32\x33\x22’ , representing each character by its hex-
adecimal code.
Long strings
We can delimit literal strings also by matching double square brackets, as we
do with long comments. Literals in this bracketed form can run for several
lines and do not interpret escape sequences. Moreover, this form ignores the
first character of the string when this character is a newline. This form is
especially convenient for writing strings that contain large pieces of code, as
in the following example:
page = [[


An HTML Page


Lua


]]
write(page)
Sometimes, you may want to enclose a piece of code containing something
like a=b[c[i]] (notice the ]] in this code), or you may need to enclose some code
that already has some code commented out. To handle such cases, you can add
any number of equal signs between the two open brackets, as in [===[ . After
this change, the literal string ends only at the next closing brackets with the
same number of equal signs in between ( ]===] , in our example). The scanner
ignores pairs of brackets with a different number of equal signs. By choosing an
appropriate number of signs, you can enclose any literal string without having
to add escapes into it.
This same facility is valid for comments, too. For instance, if you start a long
comment with –[=[ , it extends until the next ]=] . This facility allows you easily
to comment out a piece of code that contains parts already commented out.
Long strings are the ideal format to include literal text in your code, but you
should not use them for non-text literals. Although literal strings in Lua can
contain arbitrary characters, it is not a good idea to use them in your code: you
may have problems with your text editor; moreover, end-of-line sequences like
“ \r\n ” may change to “ \n ” when read. Instead, it is better to code arbitrary bi-
nary data using numeric escape sequences, either in decimal or in hexadecimal,
such as “ \x13\x01\xA1\xBB ”. However, this poses a problem for long strings,
because they would result in quite long lines.
For those situations, Lua 5.2 offers the escape sequence \z : it skips all
subsequent characters in the string until the first non-space character. The next
example illustrates its use:
data = “\x00\x01\x02\x03\x04\x05\x06\x07\z
\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F”
The \z at the end of the first line skips the following end-of-line and the inden-
tation of the next line, so that the byte \x07 is directly followed by \x08 in the
resulting string.
Coercions
Lua provides automatic conversions between numbers and strings at run time.
Any numeric operation applied to a string tries to convert the string to a number:
print(“10” + 1)
print(“10 + 1”)
print(“-5.3e-10”*”2”)
print(“hello” + 1)
–> 11
–> 10 + 1
–> -1.06e-09
– ERROR (cannot convert “hello”)
Lua applies such coercions not only in arithmetic operators, but also in other
places that expect a number, such as the argument to math.sin .
Conversely, whenever Lua finds a number where it expects a string, it con-
verts the number to a string:
print(10 .. 20)
–> 1020
(The .. is the string concatenation operator in Lua. When you write it right
after a numeral, you must separate them with a space; otherwise, Lua thinks
that the first dot is a decimal point.)
Today we are not sure that these automatic coercions were a good idea in
the design of Lua. As a rule, it is better not to count on them. They are handy
in a few places, but add complexity both to the language and to programs that
use them. After all, strings and numbers are different things, despite these
conversions. A comparison like 10 == “10” is false, because 10 is a number and
“ 10 ” is a string.
If you need to convert a string to a number explicitly, you can use the function
tonumber , which returns nil if the string does not denote a proper number:
line = io.read()
– read a line
n = tonumber(line)
– try to convert it to a number
if n == nil then
error(line .. ” is not a valid number”)
else
print(n*2)
end
To convert a number to a string, you can call the function tostring , or
concatenate the number with the empty string:
print(tostring(10) == “10”)
print(10 .. “” == “10”)
–> true
–> true
These conversions are always valid.

userdata

function

thread

table

The table type implements associative arrays. An associative array is an array
that can be indexed not only with numbers, but also with strings or any other
value of the language, except nil.
Tables are the main (in fact, the only) data structuring mechanism in Lua,
and a powerful one. We use tables to represent ordinary arrays, sets, records,
and other data structures in a simple, uniform, and efficient way. Lua uses
tables to represent packages and objects as well. When we write io.read , we
think about “the read function from the io module”. For Lua, this expression
means “index the table io using the string read as the key”.
Tables in Lua are neither values nor variables; they are objects. If you are
familiar with arrays in Java or Scheme, then you have a fair idea of what I
mean. You may think of a table as a dynamically allocated object; your program
manipulates only references (or pointers) to them. Lua never does hidden copies
or creation of new tables behind the scenes. Moreover, you do not have to declare
a table in Lua; in fact, there is no way to declare one. You create tables by means
of a constructor expression, which in its simplest form is written as {} :
a = {}
– create a table and store its reference in ‘a’
k = “x”
a[k] = 10
– new entry, with key=”x” and value=10
a[20] = “great” – new entry, with key=20 and value=”great”
print(a[“x”])
–> 10
k = 20
print(a[k])
–> “great”
a[“x”] = a[“x”] + 1
– increments entry “x”
print(a[“x”])
–> 11
A table is always anonymous. There is no fixed relationship between a
variable that holds a table and the table itself:

a = {}
a[“x”] = 10
b = a
– ‘b’ refers to the same table as ‘a’
print(b[“x”])
–> 10
b[“x”] = 20
print(a[“x”])
–> 20
a = nil
– only ‘b’ still refers to the table
b = nil
– no references left to the table
When a program has no more references to a table, Lua’s garbage collector will
eventually delete the table and reuse its memory.
Each table can store values with different types of indices, and it grows as
needed to accommodate new entries:
a = {}
– empty table
– create 1000 new entries
for i = 1, 1000 do a[i] = i*2 end
print(a[9])
–> 18
a[“x”] = 10
print(a[“x”]) –> 10
print(a[“y”]) –> nil
Note the last line: like global variables, table fields evaluate to nil when not
initialized. Also like global variables, you can assign nil to a table field to delete
it. This is not a coincidence: Lua stores global variables in ordinary tables. We
will discuss this subject further in Chapter 14.
To represent records, you use the field name as an index. Lua supports this
representation by providing a.name as syntactic sugar for a[“name”] . Therefore,
we could write the last lines of the previous example in a cleaner manner as
follows:
a.x = 10
– same as a[“x”] = 10
print(a.x)
– same as print(a[“x”])
print(a.y)
– same as print(a[“y”])
For Lua, the two forms are equivalent and can be intermixed freely. For a human
reader, however, each form may signal a different intention. The dot notation
clearly shows that we are using the table as a record, where we have some set of
fixed, predefined keys. The string notation gives the idea that the table can have
any string as a key, and that for some reason we are manipulating that specific
key.
A common mistake for beginners is to confuse a.x with a[x] . The first form
represents a[“x”] , that is, a table indexed by the string “ x ”. The second form is
a table indexed by the value of the variable x . See the difference:
a = {}
x = “y”
a[x] = 10
print(a[x])
print(a.x)
print(a.y)
–> 10
–> nil

–> 10


put 10 in field “y”
value of field “y”
value of field “x” (undefined)
value of field “y”

猜你喜欢

转载自blog.csdn.net/u013420428/article/details/80414812