跳转到内容

Lua 编程/表达式

来自维基教科书,自由的教学资源

如前所述,表达式是具有值的代码片段,可以进行评估。它们不能直接执行(函数调用除外),因此,仅包含以下代码(由表达式组成)的脚本将是错误的

3 + 5
-- The code above is erroneous because all it contains is an expression.
-- The computer cannot execute '3 + 5', since that does not make sense.

代码必须由一系列语句组成。这些语句可以包含表达式,这些表达式将是语句必须操作或用于执行指令的值。

本章中的一些代码示例不构成有效的代码,因为它们只包含表达式。在下一章中,将介绍语句,并且可以开始编写有效的代码。

评估表达式就是计算它以找到它的值。给定表达式评估到的值可能因上下文而异,因为它可能取决于环境和堆栈级别。这个值有时将是一个数字,有时是文本,有时是许多其他数据类型中的任何一个,这就是为什么它被称为具有类型。

在 Lua 中,以及在一般的编程中,表达式通常由一个或多个值和零个或多个运算符组成。某些运算符只能与某些类型一起使用(例如,试图除文本是不合逻辑的,而除数字则有意义)。运算符有两种:一元运算符和二元运算符。一元运算符是只接受一个值的运算符。例如,一元运算符 - 只接受一个数字作为参数:-5、-3、-6 等。它接受一个数字作为参数并对该数字取反。然而,二元运算符 - 与之不同,它接受两个值并将第二个值从第一个值中减去:5 - 3、8 - 6、4 - 9 等。

可以使用 type 函数以字符串形式获取数字的类型

print(type(32425)) --> number

数字通常代表数量,但它们可以用于许多其他用途。Lua 中的数字类型在大多数情况下与实数相同。数字可以构造为整数、小数、小数指数,甚至以 十六进制 形式。以下是一些有效的数字

  • 3
  • 3.0
  • 3.1416
  • 314.16e-2
  • 0.31416E1
  • 0xff
  • 0x56

算术运算

[编辑 | 编辑源代码]

Lua 中的数字运算符如下

操作 语法 描述 示例 结果
算术否定 -a 更改 a 的符号并返回该值 -3.14159
加法 a + b 返回 ab 的总和 5.2 + 3.6 8.8
减法 a - b a 中减去 b 并返回结果 6.7 - 1.2 5.5
乘法 a * b 返回 ab 的乘积 3.2 * 1.5 4.8
指数运算 a ^ b 返回 ab 次方,或 ab 乘方的结果 5 ^ 2 25
除法 a / b b 除以 a 并返回结果 6.4 / 2 3.2
向下取整除法 a // b b 除以 a 并返回结果的整数部分 6.4 // 2 3
模运算 a % b 返回 ab 除的余数 5 % 3 2

您可能已经知道所有这些运算符(它们与基本数学运算符相同),除了最后一个。最后一个称为模运算符,它简单地计算一个数字被另一个数字除的余数。例如,5 % 3 将返回 2 作为结果,因为 2 是 5 被 3 除的余数。模运算符不像其他运算符那么常见,但它有许多用途。

在 Lua 5.3 中添加了数字的一个新子类型:整数。数字可以是整数或浮点数。浮点数类似于上面描述的数字,而整数是没有任何小数部分的数字。浮点数除法 (/) 和指数运算始终将其操作数转换为浮点数,而所有其他运算符如果其两个操作数都是整数,则返回整数。在其他情况下,除了向下取整除法运算符 (//) 之外,结果将是浮点数。

Nil 是值 nil 的类型,其主要属性是与任何其他值不同;它通常表示缺少有用的值。以下是一些具有 nil 值的事物的示例

  • 您在为变量分配值之前访问它们的变量的值
  • 尝试在变量作用域之外访问变量时得到的值
  • 表中任何未分配的键的值
  • tonumber 返回的值,如果它无法将字符串转换为数字

更高级一点,有意分配 nil 值会删除对变量或表的引用,并允许 垃圾收集器 重新分配其内存。

布尔值

[编辑 | 编辑源代码]

布尔值可以是 true 或 false,但不能是其他值。在 Lua 中,它写为 truefalse,它们是保留关键字。重要的是要注意 nil 是一个不同的数据类型,如前所述。andornot() 通常与布尔值相关联,但可以在 Lua 中与任何数据类型一起使用。

操作 语法 描述
布尔值否定 not a 如果 a 为 false 或 nil,则返回 true。否则,返回 false。
逻辑连接 a and b 如果第一个参数为 false 或 nil,则返回第一个参数。否则,返回第二个参数。
逻辑析取 a or b 如果第一个参数既不是 false 也不是 nil,则返回第一个参数。否则,返回第二个参数。

本质上,not 运算符只是对布尔值取反(如果它是 true 则使其变为 false,如果它是 false 则使其变为 true),and 运算符如果两者都为 true 则返回 true,否则返回 false,而 or 运算符如果其中任何一个参数为 true 则返回 true,否则返回 false。然而,这并不是它们的工作原理,因为它们的实际工作原理如上表所述。在 Lua 中,值 false 和 nil 在逻辑表达式中都被视为 false,而其他所有内容都被视为 true(即使是 0 和空字符串)。

下一章中介绍的关系运算符 (<><=>=~===) 不一定将布尔值作为操作数,但始终会返回布尔值作为结果。

这可能难以理解。为了更清楚地说明,以下是一些真值表或表达式-结果对。这里 x 可以是 niltruefalse

表达式 结果
true and x x
false and x false
nil and x nil
true or x true
false or x x
nil or x x

这有点违反直觉,这意味着

表达式 结果
false and nil false
nil and false nil

此外,

表达式 结果
false == nil
nil == false
false
nil and false nil
表达式 结果
not(false)
not(nil)
true
not(true) false

字符串

[编辑 | 编辑源代码]

字符串是字符的序列,可以用来表示文本。它们可以在 Lua 中用双引号、单引号或长括号表示,这些在之前的关于注释的部分中已经介绍过(需要注意的是,注释和字符串除了都可以用长括号分隔之外,没有其他共同点,注释需要在长括号前面加上两个连字符)。没有用长括号括起来的字符串只持续一行。因此,要创建一个包含多行的字符串而不用长括号,唯一的方法是使用转义序列。这也是在某些情况下插入单引号或双引号的唯一方法。转义序列由两部分组成:转义字符,在 Lua 中总是反斜杠 ('\'),以及一个标识要转义的字符的标识符。

Lua 中的转义序列
转义序列 描述
\n 换行符
\" 双引号
\' 单引号(或撇号)
\\ 反斜杠
\t 水平制表符
\### ### 必须是一个从 0 到 255 的数字。结果将是对应的ASCII字符。

当直接将字符放入字符串会导致问题时,会使用转义序列。例如,如果一个字符串包含在双引号中,并且必须包含双引号,那么就需要将字符串包含在不同的字符中,或者对双引号进行转义。在用长括号分隔的字符串中转义字符是不必要的,这对所有字符都适用。用长括号分隔的字符串中的所有字符都将按原样处理。% 字符在字符串模式中用于转义魔法字符,但术语转义在另一种情况下使用。

"This is a valid string."

'This is also a valid string.'

"This is a valid \" string 'that contains unescaped single quotes and escaped double quotes."

[[
This is a line that can continue
on more than one line.

It can contain single quotes, double quotes and everything else (-- including comments). It ignores everything (including escape characters) except closing long brackets of the same level as the opening long bracket.
]]

"This is a valid string that contains tabs \t, double quotes \" and backlashes \\"

"This is " not a valid string because there is an unescaped double quote in the middle of it."

为了方便起见,如果一个开始的长字符串括号紧跟着一个换行符,那么这个换行符将被忽略。因此,以下两个字符串是等价的

[[This is a string
that can continue on many lines.]]

[[
This is a string
that can continue on many lines.]]

-- Since the opening long bracket of the second string is immediately followed by a new line, that new line is ignored.

可以使用一元长度运算符 ('#') 获取字符串的长度,以数字形式表示

print(#("This is a string")) --> 16

连接

[edit | edit source]
形式语言理论计算机编程中,字符串连接是指将两个字符字符串首尾相连的操作。例如,"snow" 和 "ball" 的连接结果是 "snowball"。
—维基百科, 连接

Lua 中的字符串连接运算符用两个点 ('..') 表示。下面是一个连接 "snow" 和 "ball" 并打印结果的例子

print("snow" .. "ball") --> snowball

这段代码将连接 "snow" 和 "ball" 并打印结果。

其他类型

[edit | edit source]

Lua 中的四种基本类型(数字、布尔值、nil 和字符串)已经在之前的部分中介绍过,但还有四种类型没有介绍:函数、表、userdata 和线程。函数是可以调用的代码片段,可以接收值并返回结果。是可以用于数据操作的数据结构。userdata是在 Lua 嵌入的应用程序内部使用的,用于允许 Lua 通过应用程序控制的对象与该程序进行通信。最后,线程由协程使用,协程允许多个函数同时运行。这些将在后面介绍,所以只需要记住还有其他的数据类型。

字面量

[edit | edit source]

字面量是在源代码中表示固定值的表示法。除了线程和 userdata 之外,所有值都可以用字面量在 Lua 中表示。字符串字面量(计算结果为字符串的字面量)例如,由字符串必须表示的文本组成,这些文本包含在单引号、双引号或长括号中。另一方面,数字字面量由它们用十进制表示法(例如:12.43)、科学计数法(例如:3.1416e-20.31416E1)或十六进制表示法(例如:0xff)表示的数字组成。

强制转换

[edit | edit source]

强制转换是指将一种数据类型的值转换为另一种数据类型的值。Lua 在字符串和数字值之间提供了自动强制转换。对字符串应用的任何算术运算都将尝试将该字符串转换为数字。相反,只要需要字符串而使用的是数字,数字就会被转换为字符串。这适用于 Lua 运算符和默认函数(与语言一起提供的函数)。

print("122" + 1) --> 123
print("The number is " .. 5 .. ".") --> The number is 5.

数字到字符串和字符串到数字的强制转换也可以使用 tostringtonumber 函数手动完成。前者接受一个数字作为参数并将其转换为字符串,而后者接受一个字符串作为参数并将其转换为数字(可以在第二个参数中选择一个与默认十进制不同的基数)。

位运算

[edit | edit source]

从 Lua 5.3 开始,提供了位运算符来对二进制数字(位模式)进行运算。这些运算符不像其他运算符那样经常使用,所以如果你不需要它们,可以跳过这一节。

Lua 中的位运算符始终对整数进行运算,如果需要会将操作数转换为整数。它们也返回整数。

按位与运算(运算符为 &)对两个二进制表示形式的相同长度的每对位执行逻辑合取。例如,5 & 3 计算结果为 1。我们可以通过查看这些数字的二进制表示来解释这一点(下标用于表示基数)

如果 5 和 3 的二进制表示中给定位置上的位都是 1(例如,最后一位),那么结果中该位置上的位将是 1;在所有其他情况下,它将是 0。

按位或运算(运算符为 |)的工作原理与按位与相同,只是它在执行逻辑合取的地方执行逻辑析取。因此,5 | 3 将计算结果为 7

在这里,我们可以看到,只有当两个操作数的二进制表示在该位置上都为 0 位时,最终结果中该位置上的位才为 0。

按位异或运算(运算符为 ~)的工作原理与其他两个运算符类似,但在给定位置上,只有当一个操作数的位为 1,而另一个操作数的位不为 1 时,最终位才为 1。

这与前面的例子相同,但我们可以看到结果中的最后一位是 0 而不是 1,因为两个操作数的最后一位都是 1。

按位取反运算(运算符为 ~)对唯一操作数的每一位执行逻辑否定,这意味着每个 0 都变成 1,每个 1 都变成 0。因此,~7 将计算结果为 -8

这里,第一个位在结果中变为 1 是因为在操作数中它是 0,其他位变为 0 是因为它们都是 1。

Left shiftRight shift

除了这些按位运算符之外,Lua 5.3 还支持算术位移。左侧的左移,运算符为<<,左侧的说明是将所有位向左移动,移动的位数与第二个操作数对应。右侧的右移,运算符为>>,右侧的说明是相同方向的反向操作。

运算符优先级

[编辑 | 编辑源代码]

运算符优先级在 Lua 中的工作方式与在数学中通常相同。某些运算符将在其他运算符之前计算,并且可以使用括号任意更改执行运算的顺序。运算符计算的优先级在下面的列表中,从最高优先级到最低优先级。其中一些运算符尚未讨论,但它们都将在本书的某个时间点介绍。

  1. 指数运算:^
  2. 一元运算符:not, #, -, ~
  3. 2 级数学运算符:*, /, //, %
  4. 1 级数学运算符:+, -
  5. 连接:..
  6. 位移:<<, >>
  7. 按位 AND:&
  8. 按位 XOR:~
  9. 按位 OR:|
  10. 关系运算符:<, >, <=, >=, ~=, ==
  11. 布尔 AND:and
  12. 布尔 OR:or

您可以回答一些问题,以验证您是否理解本章中的内容。请注意,找到某些问题的答案可能需要您拥有本章中未介绍的知识。这是正常的:测验是学习体验的一部分,它们可以介绍书中其他地方没有的信息。

1 print(type(type(5.2))) 将输出什么?

2 表达式0 or 8 将返回什么?

true
false
0
8

3 哪些字符串有效?

"test's test"
'test\'s test'
"test"s test"
'test"s test'
"test\'s test"
'test's test'

4 哪些表达式给出字符串"1223"

"122" + 3
"122" .. 3
"12" + "23"
12 .. 23

5 真或假?not 5^3 == 5

true
false

华夏公益教科书