Lua - 快速指南


Lua - 概述

Lua 是一种用 C 语言编写的可扩展的轻量级编程语言。它最初是由 Roberto Ierusalimschy、Luiz Henrique de Figueiredo 和 Waldemar Celes 于 1993 年作为内部项目启动的。

它从一开始就被设计为一个可以与用 C 和其他常规语言编写的代码集成的软件。这种集成带来了很多好处。它并不试图做 C 已经可以做的事情,而是旨在提供 C 不擅长的事情:与硬件的良好距离、动态结构、无冗余、易于测试和调试。为此,Lua 拥有安全的环境、自动内存管理以及处理字符串和其他类型的动态大小数据的良好设施。

特征

Lua 提供了一组独特的功能,使其区别于其他语言。这些包括 -

  • 可扩展
  • 简单的
  • 高效的
  • 便携的
  • 免费开放

示例代码

print("Hello World!")

Lua是如何实现的?

Lua由两部分组成——Lua解释器部分和功能软件系统。功能软件系统是一个实际的计算机应用程序,可以解释用 Lua 编程语言编写的程序。Lua解释器是用ANSI C编写的,因此它具有高度可移植性,可以在从高端网络服务器到小型设备的广泛设备上运行。

Lua 的语言及其解释器都很成熟、小巧且快速。它是从其他编程语言和顶级软件标准演变而来的。由于尺寸小,因此可以在内存较低的小型设备上运行。

学习Lua

学习 Lua 时最重要的一点是专注于概念,而不是迷失在技术细节中。

学习编程语言的目的是成为一名更好的程序员;也就是说,在设计和实施新系统以及维护旧系统方面变得更加有效。

Lua的一些用途

  • 游戏编程

  • 在独立应用程序中编写脚本

  • 网络脚本

  • MySQL Proxy 和 MySQL WorkBench 等数据库的扩展和附加组件

  • 安全系统,如入侵检测系统。

Lua - 环境

本地环境设置

如果您仍然愿意为 Lua 编程语言设置环境,您的计算机上需要有以下软件 - (a) 文本编辑器、(b) Lua 解释器和 (c) Lua 编译器。

文本编辑器

您需要一个文本编辑器来输入您的程序。一些编辑器的示例包括 Windows 记事本、操作系统编辑命令、Brief、Epsilon、EMACS 和 vim 或 vi。

文本编辑器的名称和版本可能因不同操作系统而异。例如,记事本将在 Windows 上使用,vim 或 vi 可以在 Windows 以及 Linux 或 UNIX 上使用。

您使用编辑器创建的文件称为源文件,这些文件包含程序源代码。Lua 程序的源文件通常以扩展名“.lua”命名。

Lua 解释器

它只是一个小程序,使您能够键入 Lua 命令并立即执行它们。与完全执行的编译器不同,它会在遇到错误时停止 Lua 文件的执行。

Lua编译器

当我们将Lua扩展到其他语言/应用程序时,我们需要一个带有与Lua应用程序接口兼容的编译器的软件开发工具包。

在 Windows 上安装

有一个为 windows 环境开发的名为“SciTE”的单独 IDE,可以从https://code.google.com/p/luaforwindows/下载部分下载。

运行下载的可执行文件以安装 Lua IDE。

由于它是一个 IDE,因此您可以使用它来创建和构建 Lua 代码。

如果您有兴趣以命令行方式安装Lua,则需要安装MinGW或Cygwin,然后在Windows中编译并安装Lua。

在 Linux 上安装

要下载并构建 Lua,请使用以下命令 -

$ wget http://www.lua.org/ftp/lua-5.2.3.tar.gz
$ tar zxf lua-5.2.3.tar.gz
$ cd lua-5.2.3
$ make linux test

为了在其他平台上安装,如aix、ansi、bsd、generic linux、mingw、posix、solaris,在make Linux中替换Linux,用相应的平台名称进行测试。

我们有一个 helloWorld.lua,在 Lua 中如下 -

print("Hello World!")

现在,我们可以构建并运行一个 Lua 文件(例如 helloWorld.lua),方法是使用 cd 切换到包含该文件的文件夹,然后使用以下命令 -

$ lua helloWorld

我们可以看到以下输出。

Hello World!

在 Mac OS X 上安装

要在 Mac OS X 中构建/测试 Lua,请使用以下命令 -

$ curl -R -O http://www.lua.org/ftp/lua-5.2.3.tar.gz
$ tar zxf lua-5.2.3.tar.gz
$ cd lua-5.2.3
$ make macosx test

在某些情况下,您可能尚未安装 Xcode 和命令行工具。在这种情况下,您将无法使用 make 命令。从 Mac 应用商店安装 Xcode。然后进入Xcode的Preferences,然后切换到Downloads并安装名为“Command Line Tools”的组件。该过程完成后,您将可以使用 make 命令。

您不必执行“make macosx test”语句。即使不执行此命令,您仍然可以在 Mac OS X 中使用 Lua。

我们有一个 helloWorld.lua,用 Lua 编写,如下 -

print("Hello World!")

现在,我们可以构建并运行一个 Lua 文件(例如 helloWorld.lua),方法是使用 cd 切换到包含该文件的文件夹,然后使用以下命令 -

$ lua helloWorld

我们可以看到以下输出 -

Hello World!

Lua集成开发环境

如前所述,对于 Windows SciTE,Lua IDE 是 Lua 创建者团队提供的默认 IDE。可用的替代 IDE 来自 ZeroBrane Studio,它可跨 Windows、Mac 和 Linux 等多个平台使用。

还有一些用于 eclipse 的插件可以支持 Lua 开发。使用 IDE 可以通过代码完成等功能更轻松地进行开发,强烈推荐使用。该IDE还提供类似于Lua命令行版本的交互模式编程。

Lua - 基本语法

让我们开始创建我们的第一个 Lua 程序!

第一个Lua程序

交互模式编程

Lua提供了一种模式,称为交互模式。在此模式下,您可以依次输入指令并立即获得结果。这可以在 shell 中使用 lua -i 或仅使用 lua 命令来调用。输入此内容后,按 Enter 键,交互模式将启动,如下所示。

$ lua -i 
$ Lua 5.1.4  Copyright (C) 1994-2008 Lua.org, PUC-Rio
quit to end; cd, dir and edit also available

您可以使用以下语句打印一些内容 -

print("test")

一旦你按下回车键,你将得到以下输出 -

test

默认模式编程

使用 Lua 文件名参数调用解释器将开始执行该文件,并继续执行,直到脚本完成。脚本完成后,解释器不再活动。

让我们编写一个简单的Lua程序。所有 Lua 文件的扩展名为 .lua。因此,将以下源代码放入 test.lua 文件中。

print("test")

假设 lua 环境设置正确,让我们使用以下代码运行程序 -

$ lua test.lua

我们将得到以下输出 -

test

让我们尝试另一种方式来执行 Lua 程序。以下是修改后的 test.lua 文件 -

#!/usr/local/bin/lua

print("test")

在这里,我们假设您的 /usr/local/bin 目录中有可用的 Lua 解释器。如果第一行以 # 符号开头,则解释器会忽略第一行。现在,尝试按如下方式运行该程序 -

$ chmod a+rx test.lua
$./test.lua

我们将得到以下输出。

test

现在让我们看看Lua程序的基本结构,以便您轻松了解Lua编程语言的基本构建模块。

Lua 中的代币

Lua 程序由各种标记组成,标记可以是关键字、标识符、常量、字符串文字或符号。例如,以下 Lua 语句由三个标记组成 -

io.write("Hello world, from ",_VERSION,"!\n")

各个令牌是 -

io.write
(
   "Hello world, from ",_VERSION,"!\n"
)

评论

注释就像 Lua 程序中的帮助文本一样,它们会被解释器忽略。它们以 --[[ 开头,以字符 --]] 结尾,如下所示 -

--[[ my first program in Lua --]]

身份标识

Lua 标识符是用于标识变量、函数或任何其他用户定义项的名称。标识符以字母“A 到 Z”或“a 到 z”或下划线“_”开头,后跟零个或多个字母、下划线和数字(0 到 9)。

Lua 不允许在标识符中使用标点符号,例如 @、$ 和 %。Lua 是一种区分大小写的编程语言。因此Manpowermanpower在Lua中是两个不同的标识符。以下是可接受的标识符的一些示例 -

mohd         zara      abc     move_name    a_123
myname50     _temp     j       a23b9        retVal

关键词

下面的列表显示了 Lua 中的一些保留字。这些保留字不得用作常量或变量或任何其他标识符名称。

休息 别的
否则 结尾 错误的 为了
功能 如果 当地的
不是 或者 重复
返回 然后 真的 直到
尽管

Lua 中的空白

只包含空格(可能带有注释)的行被称为空行,Lua 解释器完全忽略它。

空白是 Lua 中用来描述空白、制表符、换行符和注释的术语。空格将语句的一部分与另一部分分隔开,并使解释器能够识别语句中一个元素(例如 int)的结束位置和下一个元素的开始位置。因此,在以下声明中 -

local age

local 和 Age 之间必须至少有一个空白字符(通常是空格),以便解释器能够区分它们。另一方面,在以下声明中 -

fruit = apples + oranges   --get the total fruit

水果和 = 之间或 = 和苹果之间不需要空格字符,但如果您希望出于可读性目的,可以自由地包含一些空格字符。

Lua - 变量

变量只不过是我们的程序可以操作的存储区域的名称。它可以保存不同类型的值,包括函数和表。

变量的名称可以由字母、数字和下划线字符组成。它必须以字母或下划线开头。大小写字母是不同的,因为 Lua 区分大小写。Lua 中有八种基本类型的值 -

在Lua中,虽然我们没有变量数据类型,但根据变量的范围,我们有三种类型。

  • 全局变量- 除非明确声明为局部变量,否则所有变量都被视为全局变量。

  • 局部变量- 当变量的类型被指定为局部时,其范围受到其范围内的函数的限制。

  • 表字段- 这是一种特殊类型的变量,可以保存除 nil 之外的任何内容,包括函数。

Lua中的变量定义

变量定义意味着告诉解释器在哪里以及为变量创建存储空间的大小。变量定义具有可选类型,并包含该类型的一个或多个变量的列表,如下所示 -

type variable_list;

这里,类型可选是本地的或指定的类型使其成为全局的,并且variable_list可以由一个或多个用逗号分隔的标识符名称组成。这里显示了一些有效的声明 -

local    i, j
local    i
local    a,c

local i, j行声明并定义了变量 i 和 j;它指示解释器创建名为 i、j 的变量并将范围限制为局部。

变量可以在其声明中初始化(分配初始值)。初始化器由一个等号后跟一个常量表达式组成,如下所示 -

type variable_list = value_list;

一些例子是 -

local d , f = 5 ,10     --declaration of d and f as local variables. 
d , f = 5, 10;          --declaration of d and f as global variables. 
d, f = 10               --[[declaration of d and f as global variables. 
                           Here value of f is nil --]]

对于没有初始化器的定义:具有静态存储持续时间的变量隐式初始化为 nil。

Lua中的变量声明

正如您在上面的示例中看到的,多个变量的赋值遵循variable_list和value_list格式。在上面的示例local d, f = 5,10中,我们在变量列表中有 d 和 f,在值列表中有 5 和 10。

Lua中的赋值就像variable_list中的第一个变量和value_list中的第一个值一样发生,依此类推。因此,d 的值为 5,f 的值为 10。

例子

尝试以下示例,其中变量已在顶部声明,但它们已在主函数内定义和初始化 -

-- Variable definition:
local a, b

-- Initialization
a = 10
b = 30

print("value of a:", a)

print("value of b:", b)

-- Swapping of variables
b, a = a, b

print("value of a:", a)

print("value of b:", b)

f = 70.0/3.0
print("value of f", f)

当上面的代码构建并执行时,它会产生以下结果 -

value of a:	10
value of b:	30
value of a:	30
value of b:	10
value of f	23.333333333333

Lua 中的左值和右值

Lua中有两种表达方式:

  • 左值- 引用内存位置的表达式称为“左值”表达式。左值可以显示为赋值的左侧或右侧。

  • 右值- 术语右值是指存储在内存中某个地址的数据值。右值是不能为其赋值的表达式,这意味着右值可以出现在赋值的右侧,但不能出现在左侧。

变量是左值,因此可能出现在赋值的左侧。数字文字是右值,因此不能被赋值,也不能出现在左侧。以下是有效的声明 -

g = 20

但以下不是有效的语句,并且会生成构建时错误 -

10 = 20

在Lua编程语言中,除了上述类型的赋值之外,在同一条语句中还可以有多个左值和右值。如下所示。

g,l = 20,30

在上面的语句中,20 被赋值给 g,30 被赋值给 l。

Lua - 数据类型

Lua 是一种动态类型语言,因此变量没有类型,只有值有类型。值可以存储在变量中、作为参数传递并作为结果返回。

在Lua中,虽然我们没有变量数据类型,但是我们有值的类型。下面给出了值的数据类型列表。

先生编号 值类型和描述
1

用于区分该值是否有一些数据或没有(无)数据。

2

布尔值

包括 true 和 false 作为值。一般用于状态检查。

3

数字

表示实数(双精度浮点数)。

4

细绳

表示字符数组。

5

功能

表示用 C 或 Lua 编写的方法。

6

用户数据

表示任意 C 数据。

7

线

代表独立的执行线程,用于实现协程。

8

桌子

表示普通数组、符号表、集合、记录、图、树等,并实现关联数组。它可以保存任何值(除了 nil)。

类型 功能

在Lua中,有一个名为“type”的函数,可以让我们知道变量的类型。下面的代码给出了一些示例。

print(type("What is my type"))   --> string
t = 10

print(type(5.8*t))               --> number
print(type(true))                --> boolean
print(type(print))               --> function
print(type(nil))                 --> nil
print(type(type(ABC)))           --> string

当您构建并执行上述程序时,它会在 Linux 上产生以下结果 -

string
number
boolean
function
nil
string

默认情况下,所有变量都将指向 nil,直到它们被赋值或初始化。在 Lua 中,在条件检查的情况下,零和空字符串被认为是 true。因此,使用布尔运算时必须小心。在接下来的章节中我们将了解更多使用这些类型的信息。

Lua - 运算符

运算符是告诉解释器执行特定数学或逻辑操作的符号。Lua语言有丰富的内置运算符,并提供以下类型的运算符 -

  • 算术运算符
  • 关系运算符
  • 逻辑运算符
  • 杂项运算符

本教程将一一讲解算术运算符、关系运算符、逻辑运算符以及其他杂项运算符。

算术运算符

下表列出了Lua语言支持的所有算术运算符。假设变量A为 10,变量B为 20,则 -

显示示例

操作员 描述 例子
+ 添加两个操作数 A + B 将为 30
- 从第一个操作数中减去第二个操作数 A - B 将给出 -10
* 将两个操作数相乘 A * B 将给出 200
/ 分子除以分子 B/A 将给出 2
% 模数运算符和整数除法后的余数 B % A 将给出 0
^ 指数运算符取指数 A^2 将为 100
- 一元 - 运算符充当否定 -A 将给出 -10

关系运算符

下表列出了Lua语言支持的所有关系运算符。假设变量A为 10,变量B为 20,则 -

显示示例

操作员 描述 例子
== 检查两个操作数的值是否相等,如果相等则条件为真。 (A == B) 不正确。
〜= 检查两个操作数的值是否相等,如果值不相等则条件成立。 (A ~= B) 为真。
> 检查左操作数的值是否大于右操作数的值,如果是,则条件为真。 (A > B) 不正确。
< 检查左操作数的值是否小于右操作数的值,如果是,则条件为真。 (A < B) 为真。
>= 检查左操作数的值是否大于或等于右操作数的值,如果是,则条件为真。 (A >= B) 不正确。
<= 检查左操作数的值是否小于或等于右操作数的值,如果是,则条件为真。 (A <= B) 为真。

逻辑运算符

下表列出了Lua语言支持的所有逻辑运算符。假设变量A为 true,变量B为 false,则 -

显示示例

操作员 描述 例子
称为逻辑与运算符。如果两个操作数都不为零,则条件为真。 (A 和 B)是错误的。
或者 称为逻辑或运算符。如果两个操作数中的任何一个不为零,则条件为真。 (A 或 B)为真。
不是 称为逻辑非运算符。用于反转其操作数的逻辑状态。如果条件为真,则逻辑 NOT 运算符将为假。 !(A 和 B) 为真。

杂项运算符

Lua 语言支持的各种运算符包括连接长度

显示示例

操作员 描述 例子
.. 连接两个字符串。 a..b,其中 a 是“Hello”,b 是“World”,将返回“Hello World”。
# 返回字符串或表的长度的一元运算符。 #“Hello”将返回5

Lua中的运算符优先级

运算符优先级决定表达式中术语的分组。这会影响表达式的计算方式。某些运算符的优先级高于其他运算符;例如,乘法运算符的优先级高于加法运算符 -

例如,x = 7 + 3 * 2;这里 x 被分配为 13,而不是 20,因为运算符 * 的优先级高于 +,所以它首先乘以 3*2,然后添加到 7。

在这里,优先级最高的运算符出现在表的顶部,优先级最低的运算符出现在底部。在表达式中,将首先计算优先级较高的运算符。

显示示例

类别 操作员 关联性
一元 不是 # - 右到左
级联 .. 右到左
乘法 * / % 左到右
添加剂 + - 左到右
关系型 < > <= >= == ~=  左到右
平等 == ~= 左到右
逻辑与 左到右
逻辑或 或者 左到右

Lua - 循环

可能存在这样的情况:您需要多次执行一段代码。一般来说,语句是按顺序执行的:首先执行函数中的第一个语句,然后执行第二个语句,依此类推。

编程语言提供了各种控制结构,允许更复杂的执行路径。

循环语句允许我们多次执行一条语句或一组语句。以下是大多数编程语言中循环语句的一般形式 -

循环架构

Lua 提供了以下类型的循环来处理循环需求。

先生。 循环类型和描述
1 while 循环

当给定条件为真时,重复一个语句或一组语句。它在执行循环体之前测试条件。

2 for循环

多次执行一系列语句并缩写管理循环变量的代码。

3 重复...直到循环

重复语句组的操作,直到满足until条件。

4 嵌套循环

您可以在任何另一个while、for 或 do..while循环中使用一个或多个循环。

循环控制语句

循环控制语句改变其正常顺序的执行。当执行离开作用域时,在该作用域中创建的所有自动对象都将被销毁。

Lua支持以下控制语句。

先生。 控制语句和描述
1 中断语句

终止循环并将执行转移到紧随循环或 switch 之后的语句。

无限循环

如果条件永远不会变为假,则循环将成为无限循环。while循环通常用于此目的。由于我们直接为条件指定 true,因此它会永远执行。我们可以使用break语句来打破这个循环。

while( true )
do
   print("This loop will run forever.")
end

Lua - 决策

决策结构要求程序员指定要由程序评估或测试的一个或多个条件,以及如果条件被确定为真则要执行的一个或多个语句,以及可选的如果确定为真则要执行的其他语句条件被确定为假。

以下是大多数编程语言中典型决策结构的一般形式 -

Lua 中的决策语句

Lua 编程语言将布尔true非 nil值的任意组合假定为true,如果它是布尔falsenil,则将其假定为false值。需要注意的是,在 Lua 中,零将被视为 true。

Lua 编程语言提供以下类型的决策语句。

先生。 声明及说明
1 if 语句

if语句由一个布尔表达式后跟一个或多个语句组成。

2 if...else 语句

if语句后面可以跟一个可选的else语句,该语句在布尔表达式为 false 时执行

3 嵌套 if 语句

您可以在另一个ifelse if语句中使用一个ifelse if语句。

Lua - 函数

函数是一组共同执行任务的语句。您可以将代码划分为单独的函数。如何在不同的函数之间划分代码取决于您,但从逻辑上讲,这种划分通常是唯一的,因此每个函数都执行特定的任务。

Lua 语言提供了许多您的程序可以调用的内置方法。例如,方法print()用于打印在控制台中作为输入传递的参数。

函数有各种名称,例如方法、子例程或过程等。

定义函数

Lua 编程语言中方法定义的一般形式如下 -

optional_function_scope function function_name( argument1, argument2, argument3........, 
argumentn)
function_body
return result_params_comma_separated
end

Lua编程语言中的方法定义由方法头方法体组成。以下是方法的所有部分 -

  • 可选函数作用域- 您可以使用关键字local来限制函数的作用域或忽略作用域部分,这将使其成为全局函数。

  • 函数名称- 这是函数的实际名称。函数名和参数列表共同构成函数签名。

  • 参数- 参数就像占位符。当调用函数时,您将一个值传递给参数。该值称为实际参数或参数。参数列表是指方法的参数的类型、顺序和数量。参数是可选的;也就是说,方法可以不包含参数。

  • 函数体- 方法体包含定义该方法功能的语句集合。

  • Return - 在Lua中,可以通过在return关键字后面加上逗号分隔的返回值来返回多个值。

例子

以下是名为max()的函数的源代码。该函数采用两个参数 num1 和 num2 并返回两者之间的最大值 -

--[[ function returning the max between two numbers --]]
function max(num1, num2)

   if (num1 > num2) then
      result = num1;
   else
      result = num2;
   end

   return result; 
end

函数参数

如果函数要使用参数,则它必须声明接受参数值的变量。这些变量称为函数的形式参数。

形式参数的Behave与函数内的其他局部变量类似,在进入函数时创建并在退出时销毁。

调用函数

创建 Lua 函数时,您需要定义该函数必须执行的操作。要使用方法,您必须调用该函数来执行定义的任务。

当程序调用函数时,程序控制权将转移到被调用的函数。被调用函数执行定义的任务,当执行其返回语句或到达其函数末尾时,它将程序控制权返回给主程序。

要调用方法,您只需传递所需的参数以及方法名称,如果该方法返回一个值,那么您可以存储返回值。例如 -

function max(num1, num2)

   if (num1 > num2) then
      result = num1;
   else
      result = num2;
   end

   return result; 
end

-- calling a function
print("The maximum of the two numbers is ",max(10,4))
print("The maximum of the two numbers is ",max(5,6))

当我们运行上面的代码时,我们将得到以下输出。

The maximum of the two numbers is 	10
The maximum of the two numbers is 	6

分配和传递函数

在Lua中,我们可以将函数分配给变量,也可以将它们作为另一个函数的参数传递。这是一个在 Lua 中分配和传递函数作为参数的简单示例。

myprint = function(param)
   print("This is my print function -   ##",param,"##")
end

function add(num1,num2,functionPrint)
   result = num1 + num2
   functionPrint(result)
end

myprint(10)
add(2,5,myprint)

当我们运行上面的代码时,我们将得到以下输出。

This is my print function -   ##	10	##
This is my print function -   ##	7	##

带有变量参数的函数

在 Lua 中可以使用“...”作为参数创建带有可变参数的函数。我们可以通过看一个示例来理解这一点,在该示例中,函数将返回平均值并且可以接受可变参数。

function average(...)
   result = 0
   local arg = {...}
   for i,v in ipairs(arg) do
      result = result + v
   end
   return result/#arg
end

print("The average is",average(10,5,3,4,5,6))

当我们运行上面的代码时,我们将得到以下输出。

The average is	5.5

Lua - 字符串

字符串是字符序列以及控制字符(如换页符)。字符串可以用三种形式初始化,其中包括 -

  • 单引号之间的字符
  • 双引号之间的字符
  • [[ 和 ]] 之间的字符

上述三种形式的示例如下所示。

string1 = "Lua"
print("\"String 1 is\"",string1)

string2 = 'Tutorial'
print("String 2 is",string2)

string3 = [["Lua Tutorial"]]
print("String 3 is",string3)

当我们运行上面的程序时,我们将得到以下输出。

"String 1 is" Lua
String 2 is	Tutorial
String 3 is	"Lua Tutorial"

字符串中使用转义序列字符来更改字符的正常解释。例如,要打印双引号 (""),我们在上面的示例中使用了 \"。下表列出了转义序列及其用途。

转义序列 使用
\A
\b 退格键
\F 换页
\n 新队
\r 回车符
\t 标签
\v 垂直标签
\\ 反斜杠
\" 双引号
\' 单引号
\[ 左方括号
\] 右方括号

字符串操作

Lua 支持 string 来操作字符串 -

先生。 方法与目的
1

字符串.upper(参数)

返回参数的大写表示形式。

2

字符串.lower(参数)

返回参数的小写表示形式。

3

string.gsub(mainString,findString,replaceString)

通过用replaceString 替换出现的findString 来返回字符串。

4

字符串.find(mainString,findString,

可选开始索引,可选结束索引)

返回主字符串中 findString 的起始索引和结束索引,如果未找到则返回 nil。

5

字符串.reverse(arg)

通过反转传递的字符串的字符来返回字符串。

6

字符串.format(...)

返回格式化的字符串。

7

string.char(arg) 和 string.byte(arg)

返回输入参数的内部数字和字符表示形式。

8

字符串.len(arg)

返回传递的字符串的长度。

9

string.rep(字符串, n))

通过重复相同的字符串 n 次来返回一个字符串。

10

..

因此运算符连接两个字符串。

现在,让我们深入研究几个示例,以准确了解这些字符串操作函数的Behave方式。

案例处理

下面给出了将字符串转换为大写和小写的示例代码。

string1 = "Lua";

print(string.upper(string1))
print(string.lower(string1))

当我们运行上面的程序时,我们将得到以下输出。

LUA
lua

替换子字符串

下面给出了用另一个字符串替换出现的一个字符串的示例代码。

string = "Lua Tutorial"

-- replacing strings
newstring = string.gsub(string,"Tutorial","Language")
print("The new string is "..newstring)

当我们运行上面的程序时,我们将得到以下输出。

The new string is Lua Language

寻找和逆转

下面给出了查找子字符串索引和反转字符串的示例代码。

string = "Lua Tutorial"

-- replacing strings
print(string.find(string,"Tutorial"))
reversedString = string.reverse(string)
print("The new string is",reversedString)

当我们运行上面的程序时,我们将得到以下输出。

5	12
The new string is	lairotuT auL

格式化字符串

很多时候在我们的编程中,我们可能需要以格式化的方式打印字符串。您可以使用 string.format 函数来格式化输出,如下所示。

string1 = "Lua"
string2 = "Tutorial"

number1 = 10
number2 = 20

-- Basic string formatting
print(string.format("Basic formatting %s %s",string1,string2))

-- Date formatting
date = 2; month = 1; year = 2014
print(string.format("Date formatting %02d/%02d/%03d", date, month, year))

-- Decimal formatting
print(string.format("%.4f",1/3))

当我们运行上面的程序时,我们将得到以下输出。

Basic formatting Lua Tutorial
Date formatting 02/01/2014
0.3333

字符和字节表示

字符和字节表示的示例代码,用于将字符串从字符串转换为内部表示,反之亦然。

-- Byte conversion

-- First character
print(string.byte("Lua"))

-- Third character
print(string.byte("Lua",3))

-- first character from last
print(string.byte("Lua",-1))

-- Second character
print(string.byte("Lua",2))

-- Second character from last
print(string.byte("Lua",-2))

-- Internal Numeric ASCII Conversion
print(string.char(97))

当我们运行上面的程序时,我们将得到以下输出。

76
97
97
117
117
a

其他常用功能

常见的字符串操作包括字符串连接、查找字符串长度以及有时多次重复同一字符串。下面给出了这些操作的示例。

string1 = "Lua"
string2 = "Tutorial"

-- String Concatenations using ..
print("Concatenated string",string1..string2)

-- Length of string
print("Length of string1 is ",string.len(string1))

-- Repeating strings
repeatedString = string.rep(string1,3)
print(repeatedString)

当我们运行上面的程序时,我们将得到以下输出。

Concatenated string	LuaTutorial
Length of string1 is 	3
LuaLuaLua

Lua - 数组

数组是对象的有序排列,可以是包含行集合的一维数组,也可以是包含多行和多列的多维数组。

在Lua中,数组是使用整数索引表来实现的。数组的大小不是固定的,它可以根据我们的要求增长,但受到内存限制。

一维数组

一维数组可以使用简单的表结构来表示,并且可以使用简单的for循环来初始化和读取。一个例子如下所示。

array = {"Lua", "Tutorial"}

for i = 0, 2 do
   print(array[i])
end

当我们运行上面的代码时,我们将得到以下输出。

nil
Lua
Tutorial

正如您在上面的代码中看到的,当我们尝试访问索引中不存在于数组中的元素时,它返回 nil。在Lua中,索引通常从索引1开始。但也可以在索引0及0以下创建对象。使用负索引的数组如下所示,我们使用for循环初始化数组。

array = {}

for i= -2, 2 do
   array[i] = i *2
end

for i = -2,2 do
   print(array[i])
end

当我们运行上面的代码时,我们将得到以下输出。

-4
-2
0
2
4

多维数组

多维数组可以通过两种方式实现。

  • 数组的数组
  • 通过操作索引的一维数组

下面使用数组的数组显示了 3. 3 的多维数组的示例。

-- Initializing the array
array = {}

for i=1,3 do
   array[i] = {}
	
   for j=1,3 do
      array[i][j] = i*j
   end
	
end

-- Accessing the array

for i=1,3 do

   for j=1,3 do
      print(array[i][j])
   end
	
end

当我们运行上面的代码时,我们将得到以下输出。

1
2
3
2
4
6
3
6
9

下面显示了使用操作索引的多维数组的示例。

-- Initializing the array

array = {}

maxRows = 3
maxColumns = 3

for row=1,maxRows do

   for col=1,maxColumns do
      array[row*maxColumns +col] = row*col
   end
	
end

-- Accessing the array

for row=1,maxRows do

   for col=1,maxColumns do
      print(array[row*maxColumns +col])
   end
	
end

当我们运行上面的代码时,我们将得到以下输出。

1
2
3
2
4
6
3
6
9

正如您在上面的示例中看到的,数据是基于索引存储的。可以以稀疏的方式放置元素,这就是矩阵 Lua 实现的工作方式。由于 Lua 中不存储 nil 值,因此与其他编程语言中使用的特殊技术相比,Lua 中无需任何特殊技术就可以节省大量内存。

Lua - 迭代器

迭代器是一种构造,使您能够遍历所谓的集合或容器的元素。在Lua中,这些集合通常指的是表,它们用于创建各种数据结构,例如数组。

泛型迭代器

泛型for迭代器提供集合中每个元素的键值对。下面给出一个简单的例子。

array = {"Lua", "Tutorial"}

for key,value in ipairs(array) 
do
   print(key, value)
end

当我们运行上面的代码时,我们将得到以下输出 -

1  Lua
2  Tutorial

上面的例子使用了Lua提供的默认的ipairs迭代器函数。

在Lua中我们使用函数来表示迭代器。基于这些迭代器函数中的状态维护,我们有两种主要类型 -

  • 无状态迭代器
  • 有状态迭代器

无状态迭代器

从名称本身我们就可以理解这种类型的迭代器函数不保留任何状态。

现在让我们看一个使用打印n 个数字的平方的简单函数创建我们自己的迭代器的示例。

function square(iteratorMaxCount,currentNumber)

   if currentNumber<iteratorMaxCount
   then
      currentNumber = currentNumber+1
      return currentNumber, currentNumber*currentNumber
   end
	
end

for i,n in square,3,0
do
   print(i,n)
end

当我们运行上面的程序时,我们将得到以下输出。

1	1
2	4
3	9

可以稍微修改上面的代码以模仿迭代器的ipairs函数的工作方式。如下所示。

function square(iteratorMaxCount,currentNumber)

   if currentNumber<iteratorMaxCount
   then
      currentNumber = currentNumber+1
      return currentNumber, currentNumber*currentNumber
   end
	
end

function squares(iteratorMaxCount)
   return square,iteratorMaxCount,0
end  

for i,n in squares(3)
do 
   print(i,n)
end

当我们运行上面的程序时,我们将得到以下输出。

1	1
2	4
3	9

有状态迭代器

前面使用函数进行迭代的示例不保留状态。每次调用该函数时,它都会根据发送到该函数的第二个变量返回集合的下一个元素。为了保存当前元素的状态,使用了闭包。闭包在函数调用之间保留变量值。为了创建一个新的闭包,我们创建两个函数,包括闭包本身和一个工厂,即创建闭包的函数。

现在让我们看一个创建我们自己的迭代器的示例,我们将在其中使用闭包。

array = {"Lua", "Tutorial"}

function elementIterator (collection)

   local index = 0
   local count = #collection
	
   -- The closure function is returned
	
   return function ()
      index = index + 1
		
      if index <= count
      then
         -- return the current element of the iterator
         return collection[index]
      end
		
   end
	
end

for element in elementIterator(array)
do
   print(element)
end

当我们运行上面的程序时,我们将得到以下输出。

Lua
Tutorial

在上面的示例中,我们可以看到 elementIterator 内部还有另一个方法,它使用局部外部变量 index 和 count 来通过每次调用函数时递增索引来返回集合中的每个元素。

我们可以使用闭包创建我们自己的函数迭代器,如上所示,它可以在每次迭代集合时返回多个元素。

Lua - 表

介绍

表是 Lua 中唯一可用的数据结构,可以帮助我们创建不同的类型,例如数组和字典。Lua 使用关联数组,它不仅可以用数字索引,还可以用除 nil 之外的字符串索引。表没有固定的大小,可以根据我们的需要进行增长。

Lua 在所有表示中都使用表,包括包的表示。当我们访问 string.format 方法时,这意味着我们正在访问 string 包中可用的 format 函数。

表示和使用

表称为对象,它们既不是值也不是变量。Lua 使用构造函数表达式 {} 创建一个空表。应该知道,保存表引用的变量与表本身之间没有固定的关系。

--sample table initialization
mytable = {}

--simple table value assignment
mytable[1]= "Lua"

--removing reference
mytable = nil

-- lua garbage collection will take care of releasing memory

当我们有一个包含一组元素的表a并将其分配给b时,ab都引用相同的内存。没有为 b 单独分配单独的内存。当a设置为nil时,b仍然可以访问表。当没有对表的引用时,Lua 中的垃圾收集会负责清理过程,以使这些未引用的内存再次被重用。

下面用一个例子来解释上述表格的特点。

-- Simple empty table
mytable = {}
print("Type of mytable is ",type(mytable))

mytable[1]= "Lua"
mytable["wow"] = "Tutorial"

print("mytable Element at index 1 is ", mytable[1])
print("mytable Element at index wow is ", mytable["wow"])

-- alternatetable and mytable refers to same table
alternatetable = mytable

print("alternatetable Element at index 1 is ", alternatetable[1])
print("alternatetable Element at index wow is ", alternatetable["wow"])

alternatetable["wow"] = "I changed it"

print("mytable Element at index wow is ", mytable["wow"])

-- only variable released and and not table
alternatetable = nil
print("alternatetable is ", alternatetable)

-- mytable is still accessible
print("mytable Element at index wow is ", mytable["wow"])

mytable = nil
print("mytable is ", mytable)

当我们运行上面的程序时,我们将得到以下输出 -

Type of mytable is 	table
mytable Element at index 1 is 	Lua
mytable Element at index wow is 	Tutorial
alternatetable Element at index 1 is 	Lua
alternatetable Element at index wow is 	Tutorial
mytable Element at index wow is 	I changed it
alternatetable is 	nil
mytable Element at index wow is 	I changed it
mytable is 	nil

表操作

有用于表操作的内置函数,下表列出了它们。

先生。 方法与目的
1

table.concat(表[,sep[,i[,j]]])

根据给定的参数连接表中的字符串。详细信息请参见示例。

2

table.insert(表,[pos,]值)

将值插入到表中的指定位置。

3

表.maxn(表)

返回最大的数字索引。

4

table.remove(表[, pos])

从表中删除该值。

5

table.sort(表[,comp])

根据可选的比较器参数对表进行排序。

让我们看一下上述函数的一些示例。

表串联

我们可以使用 concat 函数连接两个表,如下所示 -

fruits = {"banana","orange","apple"}

-- returns concatenated string of table
print("Concatenated string ",table.concat(fruits))

--concatenate with a character
print("Concatenated string ",table.concat(fruits,", "))

--concatenate fruits based on index
print("Concatenated string ",table.concat(fruits,", ", 2,3))

当我们运行上面的程序时,我们将得到以下输出 -

Concatenated string 	bananaorangeapple
Concatenated string 	banana, orange, apple
Concatenated string 	orange, apple

插入和删除

在表操作中,插入和删除表中的项目是最常见的。下面对此进行解释。

fruits = {"banana","orange","apple"}

-- insert a fruit at the end
table.insert(fruits,"mango")
print("Fruit at index 4 is ",fruits[4])

--insert fruit at index 2
table.insert(fruits,2,"grapes")
print("Fruit at index 2 is ",fruits[2])

print("The maximum elements in table is",table.maxn(fruits))

print("The last element is",fruits[5])

table.remove(fruits)
print("The previous last element is",fruits[5])

当我们运行上面的程序时,我们将得到以下输出 -

Fruit at index 4 is 	mango
Fruit at index 2 is 	grapes
The maximum elements in table is	5
The last element is	mango
The previous last element is	nil

排序表

我们经常需要按特定顺序对表进行排序。排序函数按字母顺序对表中的元素进行排序。下面显示了一个示例。

fruits = {"banana","orange","apple","grapes"}

for k,v in ipairs(fruits) do
   print(k,v)
end

table.sort(fruits)
print("sorted table")

for k,v in ipairs(fruits) do
   print(k,v)
end

当我们运行上面的程序时,我们将得到以下输出 -

1	banana
2	orange
3	apple
4	grapes
sorted table
1	apple
2	banana
3	grapes
4	orange

Lua - 模块

什么是模块?

模块就像一个可以使用require加载的库,并且具有包含表的单个全局名称。该模块可以由许多函数和变量组成。所有这些函数和变量都包装在表中,该表充当命名空间。此外,一个表现良好的模块有必要的规定来根据需要返回该表。

Lua模块的特殊性

在模块中使用表可以在很多方面帮助我们,并使我们能够像操作任何其他 Lua 表一样操作模块。由于能够操作模块,它提供了其他语言需要特殊机制的额外功能。由于Lua中模块的这种自由机制,用户可以通过多种方式调用Lua中的函数。下面显示了其中的一些。

-- Assuming we have a module printFormatter
-- Also printFormatter has a funtion simpleFormat(arg)
-- Method 1
require "printFormatter"
printFormatter.simpleFormat("test")

-- Method 2
local formatter = require "printFormatter"
formatter.simpleFormat("test")

-- Method 3
require "printFormatter"
local formatterFunction = printFormatter.simpleFormat
formatterFunction("test")

在上面的示例代码中,您可以看到Lua编程是多么灵活,无需任何特殊的额外代码。

需要的函数

Lua 提供了一个名为require的高级函数来加载所有必需的模块。它尽可能简单,以避免模块上有太多信息来加载它。require 函数只是假设模块是定义一些值的代码块,这些值实际上是函数或包含函数的表。

例子

让我们考虑一个简单的例子,其中一个函数具有数学函数。我们将此模块命名为 mymath,文件名为 mymath.lua。文件内容如下 -

local mymath =  {}

function mymath.add(a,b)
   print(a+b)
end

function mymath.sub(a,b)
   print(a-b)
end

function mymath.mul(a,b)
   print(a*b)
end

function mymath.div(a,b)
   print(a/b)
end

return mymath	

现在,为了在另一个文件(例如 moduletutorial.lua)中访问此 Lua 模块,您需要使用以下代码段。

mymathmodule = require("mymath")
mymathmodule.add(10,20)
mymathmodule.sub(30,20)
mymathmodule.mul(10,20)
mymathmodule.div(30,20)

为了运行此代码,我们需要将两个 Lua 文件放在同一目录中,或者,您可以将模块文件放在包路径中,它需要额外的设置。当我们运行上面的程序时,我们将得到以下输出。