位置:首页 > Lua > 深入解析 Lua 核心数据类型与表的高级应用

深入解析 Lua 核心数据类型与表的高级应用

时间:2026-08-27  |  作者:夜鞌不睡  |  阅读:0

目录

  1. 1 数据类型
  2. 2 字符串(string)
  3. 3 数值类型(number)
  4. 4 布尔类型(boolean)
  5. 5 表(table)
  6. 5.1 全局表 _G

前言

Lua 语言提供了八种基础数据类型,涵盖字符串、数值、布尔值及函数等,是构建程序逻辑的基石。本文详细解析各类特性,重点探讨字符串的多重定义方式与数值处理机制。同时深入剖析核心数据结构表(table),阐述其作为哈希表的灵活用法,并介绍全局表 _G 的管理机制。此外,还通过复制表与函数闭包两种路径,演示如何利用表实现面向对象编程,帮助开发者全面掌握 Lua 数据操作精髓。

深入解析 Lua 核心数据类型与表的高级应用 的核心流程信息图
深入解析 Lua 核心数据类型与表的高级应用用简体中文信息图概括深入解析 Lua 核心数据类型与表的高级应用的核心流程、关键规则与实践要点。

1 数据类型

Lua 语言提供了丰富的数据类型,用于处理各种数据。主要包含以下八种类型:

数据类型 对应的技术说明图
数据类型概括数据类型的核心概念、关键要点与实践提示。
  • 字符串(string):由双引号或者单引号括起来的字符序列。
  • 数值类型(number):涵盖所有数字形式,包括十进制、十六进制以及科学计数法等表示方法。
  • 布尔类型(boolean):仅包含真和假两个值,分别对应 true 和 false。
  • 函数(function):封装了特定功能的代码块,可作为值传递。
  • 表(table):Lua 语言的核心数据结构,类似于哈希表,用于存储关联数据。
  • 自定义类型(userdata):由应用程序定义的类型,脚本用户只能使用,不能直接定义其结构。
  • 线程(thread):表示协同程序,用于实现异步计算,是一种轻量级有限线程。
  • 空类型(nil):表示“空”或“无”,代表变量没有值。

在 Lua 编程中,可以使用 type 函数来查询并确定变量当前的数据类型。

理解这些基础类型是掌握 Lua 编程的关键,它们构成了所有数据操作的基础。

2 字符串(string)

在 Lua 中,双引号和单引号括起来的字符串在使用上没有区别,两者均支持对转义字符进行正确转义处理。

字符串(string) 对应的技术说明图
字符串(string)概括字符串(string)的核心概念、关键要点与实践提示。

此外,字符串还可以使用两个成对的中括号([[ ]])来包含。这种方式用于存储字符串的原始值,即使字符串内容跨越多行,也能保持原样,非常适合处理大段文本或包含特殊字符的字符串。

3 数值类型(number)

数值类型涵盖了 Lua 中所有的数字表示形式。这包括常见的十进制整数、浮点数,以及十六进制表示法和科学计数法表示的数值。Lua 内部通常将数值统一处理为双精度浮点数,以支持广泛的数学运算。

4 布尔类型(boolean)

布尔类型是最简单的数据类型之一,仅包含两个预定义的值:true(真)和 false(假)。它们常用于条件判断和控制流语句中,决定代码的执行路径。

5 表(table)

表是 Lua 中最重要的数据结构,用来存储互相关联的元素。每个元素由一个关键字(key)和一个值(value)组成,形成键值对结构。表的功能类似于其他语言中的哈希表或字典。

表中元素的值可以是任何类型的值,包括字符串、数值、其他表、函数等,这使得表具有极高的灵活性和扩展性。

对表中元素的引用,除了使用 表名[键名] 语法之外,还可以使用 表名.键名 语法。需要注意的是,后面这种点号引用方式不可以引用键是数值的元素,而方括号方式则更为通用。

5.1 全局表 _G

在 Lua 中,所有定义的全局变量都会自动存储在一个名为 _G 的特殊表中。这个全局表充当了全局命名空间的容器,使得我们可以通过访问该表的键来读取或修改变量的值。这种机制不仅简化了全局变量的管理,也为动态访问变量提供了便利。例如,通过 _G 表,我们可以动态地获取或设置任意全局变量的值,这在编写通用工具函数或框架时非常有用。

5.2 复制表方式实现面向对象

Lua 虽然没有内置的类概念,但可以通过表来模拟面向对象编程。由于表可以存储键值对,并且可以将函数赋值给表的键,因此我们可以将表视为一个类。通过这种方式,我们可以定义类的属性和方法,并创建该类的实例。

为了实现对象的创建,我们可以定义一个函数,用于克隆上面定义的 Person 表的元素。这个函数会生成一个新的表,模拟生成新对象的过程。通过这种方式,我们可以创建多个具有相同属性和方法的对象实例,从而实现面向对象编程的基本功能。

此外,我们可以在表 Person 中定义一个名为 new 的函数。这个函数可以接收参数,从而构造具有指定参数的对象。例如,我们可以定义一个构造函数,接收姓名和年龄作为参数,并返回一个新的对象表。这种方式使得对象的创建更加灵活和可控。

除了基本的对象创建,我们还可以模拟类之间的继承关系。通过将一个类的表作为另一个类的父表,我们可以实现属性的继承和方法的重写。这种方式使得代码更加模块化和可复用,符合面向对象编程的设计原则。

5.3 函数闭包方式实现面向对象

另一种实现面向对象编程的方式是使用函数闭包。我们可以定义一个函数,该函数返回一个表(对象),并通过闭包机制保留局部变量的状态。这种方式使得对象的内部状态更加安全,因为外部无法直接访问这些局部变量。

例如,我们可以定义一个函数,该函数创建一个包含私有变量的表,并返回一个包含方法的表。这些方法可以访问和操作私有变量,从而实现封装的效果。通过这种方式,我们可以实现更加复杂的面向对象结构。

同样,模拟类继承关系也可以使用函数闭包的方式。通过将一个类的闭包函数作为另一个类的父函数,我们可以实现属性的继承和方法的重写。这种方式使得代码更加灵活,同时也保持了面向对象编程的核心思想。

6 函数

函数的基本特性与返回值

在 Lua 中,函数被视为 function 类型的对象。这一特性赋予了函数极高的灵活性:它们可以被赋值给变量,能够作为其他函数的返回值,支持相互比较,并且可以作为 table 表中的值存储。这种一等公民的地位使得函数在 Lua 编程中扮演着核心角色。

Return 关键字的使用规则

函数可以选择不返回值,也可以返回单个值或多个值。需要注意的是,return 关键字的使用位置受到严格限制,它只能出现在代码块的末尾,具体而言,必须位于 end、else 或者 until 关键字之前。这一规则确保了控制流的清晰性和代码的可读性。

多值返回与赋值机制

Lua 处理函数返回值时遵循特定的规则。如果函数的返回值是另一个函数的最后一个参数,或者是多值赋值表达式中的最后一个参数,那么该函数的所有返回值都会被保留并使用。反之,如果不符合上述条件,则只有第一个返回值会被使用,其余返回值将被丢弃。这一机制在处理复杂数据传递时尤为重要。

可变参数与尾调用优化

Lua 支持定义可变参数的函数,允许函数接收不定数量的参数。此外,当函数的最后返回值是调用另一个函数时,这种结构被称为尾调用。Lua 在实现尾调用优化时,会先弹出当前函数的栈空间,然后再调用目标函数。这种机制显著降低了函数层层调用过程中的栈消耗,特别适用于需要深度递归调用的场景,从而提高了程序的性能和稳定性。

本次分享到此结束啦~~

如果觉得文章对你有帮助,点赞、收藏、关注、评论,您的支持就是我创作最大的动力!

 print(type("chenpi")) -- string
 print(type(123)) -- number
 print(type(true)) -- boolean
 print(type(type)) -- function
 print(type({})) -- table
 > print('单引号括起来的字符串nr这是换行后内存!')
 单引号括起来的字符串
 这是换行后内存!
 > print("双引号括起来的字符串nr这是换行后内存!")
 双引号括起来的字符串
 这是换行后内存!
 > 
 str = [[aa
 bb cc
 dd
   ee
 ff ff ff
 ]]
 print(str)
 
 -- 输出结果如下
 aa
 bb cc
 dd
   ee
 ff ff ff
 i = 10
 j = 10.15
 k = 0x12
 h = 1.20e5
 
 print(i) -- 10
 print(j) -- 10.15
 print(k) -- 18
 print(h) -- 120000.0
 flag = true
 
 if flag then
   print("flag is true")
 else
   print("flag is false")
 end
 
 -- 输出 flag is true
 -- 创建一个空表
 t = {}
 
 -- 没有显示指定键的值,系统会自动分配键1,2,3...
 t = {k1 ="v1", "a", "b", "c"}
 print(t[0])      -- nil
 print(t[1])      -- a
 print(t[2])      -- b
 print(t[3])      -- c
 print(t[4])      -- nil
 print(t["k1"])   -- v1
 t = {k1 ="a", "b", k2 = "c", "d"}
 print(t[1])      -- b
 print(t[2])      -- d
 print(t["k1"])   -- a
 print(t.k1)      -- a
 -- print(t.1)    -- 不合法,会报错
 
 t.k1 = "aa"
 t[1] = "bb"
 print(t[1])      -- bb
 print(t.k1)      -- aa
 t = {k1 ="a", k2 = "b"}
 print(t.k1)      -- a
 t.k1 = nil
 print(t.k1)      -- nil
t = {k1 ="a", "b", k2 = "c", "d"}

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

-- 输出结果如下
1       b
2       d
k2      c
k1      a
t = {}

t.func = function()
	print("Hello ChenPi!")
end

function t.func()
  print("Hello ChenPi!")
end

--[[
上面和此种方式一样,但是推荐使用上面的方式
function t.func()
  print("Hello ChenPi!")
end
--]]

t.func()  -- Hello ChenPi!
-- 插入元素,删除元素
table.insert(表名, 键, 值)
table.remove(表名, 键)

t = {"a", "b", "c"}
table.insert(t, 2, "g")  -- 在第二个位置插入元素,原来键为2的值依次往后移
table.insert(t, "f")     -- 没有指定键,则插入到尾部

-- 输出 agbcf
for i = 1, #t do
    print(t[i])
end

table.remove(t, 2)    -- 删除键为2的元素
table.remove(t)       -- 省略键,则删除最后一个元素

-- 输出 abc
for i = 1, #t do
    print(t[i])
end

-- 排序函数
table.sort(表名, 排序规则)  -- 排序规则可以省略
t = {"d", "a", "e", "c", "h", "g"}
table.sort(t) -- 对值进行排序
-- 输出 acdegh
for i = 1, #t do
    print(t[i])
end

function mysort(a, b)
    return a > b
end
table.sort(t, mysort)
-- 输出 hgedca
for i = 1, #t do
    print(t[i])
end
-- 定义一个空表
chenpifunc = {}

-- 定义第一个函数
chenpifunc.func1 = function()
	print("Hello ChenPi!")
end

-- 定义第二个函数
chenpifunc.func2 = function(a, b)
	local r = a + b
	return r
end

-- 使用函数库
chenpifunc.func1()
print(chenpifunc.func2(5, 8))

-- 输出结果如下
Hello ChenPi!
13
arr = {1, 2, "a", "b", 3, true, 10.51}

-- 打印的数数组的地址
print(arr)

-- 遍历数组
for k, v in pairs(arr) do
  print(k, v)
end

-- 打印数组类型
print(type(arr))

-- 输出结果如下
table: 0x2406730
1       1
2       2
3       a
4       b
5       3
6       true
7       10.51
table
 name = "陈皮"
 age = 18
 print(_G["name"])  -- 陈皮
 print(_G.age)  -- 18
 
 t = {name = "Hello Lua"}
 
 func = function()
   print("Hi func")
 end
 
 print(_G["t"]["name"])  -- Hello Lua
 _G.func()  -- Hi func
 -- 定义一个表,代表一个类模板
 Person = {}
 Person.name = "ChenPi"
 Person.eat = function(p)
   print(p.name.." is eating")
 end
 
 print(Person.name) -- ChenPi
 Person.eat(Person) -- ChenPi is eating
 function clone(t)
   local inst = {}
   for k, v in pairs(t) do
     inst[k] = v
   end
   return inst
 end
 
 -- 定义一个表,代表一个类模板
 Person = {}
 Person.name = "ChenPi"
 Person.eat = function(p)
   print(p.name.." is eating")
 end
 
 -- 克隆对象
 local p = clone(Person)
 print(p.name) -- Hi ChenPi
 p.eat(p) -- I am eating
 p:eat() -- I am eating 等同于调用eat函数,并把自身作为参数传入函数
 function clone(t)
   local inst = {}
   for k, v in pairs(t) do
     inst[k] = v
   end
   return inst
 end
 
 -- 定义一个表,代表一个类模板
 Person = {}
 Person.name = "ChenPi"
 Person.eat = function(p)
   print(p.name.." is eating")
 end
 
 Person.new = function(name)
   local self = clone(Person)
   self.name = name
   return self
 end
 
 
 -- 克隆对象
 local p = Person.new("陈皮")
 print(p.name) -- 陈皮
 p:eat() -- 皮 is eating
 function clone(t)
   local inst = {}
   for k, v in pairs(t) do
     inst[k] = v
   end
   return inst
 end
 
 -- 定义一个表,代表一个类模板
 Person = {}
 Person.name = "ChenPi"
 Person.eat = function(p)
   print(p.name.." is eating")
 end
 
 Person.new = function(name)
   local self = clone(Person)
   self.name = name
   return self
 end
 
 -- 子类定义
 Student = {age = 18}
 Student.study = function()
   print("Student is studying...")
 end
     
 Student.new = function(name)
   local self = Person.new(name)
   -- 将子类的元素放入父类中,重复的键还可以达到重写作用
   for k, v in pairs(Student) do
     self[k] = v
   end
   return self
 end
 
 -- 创建子类对象
 local s = Student.new("陈皮")
 print(s.name) -- 陈皮
 print(s.age)  -- 18
 s:eat() -- 陈皮 is eating
 s.study() -- Student is studying...
 function Person(name)
   local self = {}
   self.name = name
   self.eat = function(p)
     print(p.name.." is eating")
   end
   return self
 end
 
 local p = Person("陈皮")
 p:eat() -- 陈皮 is eating
 function Person(name)
   local self = {}
   self.name = name
   self.eat = function(p)
     print(p.name.." is eating")
   end
   return self
 end
 
 local p = Person("陈皮")
 p:eat() -- 陈皮 is eating
 
 function Student(name)
   local self = Person(name)
   self.study = function()
     print(self.name.." is studying...")
   end
   return self
 end
 
 local s = Student("狗蛋")
 s:eat()  -- 狗蛋 is eating
 s.study()  -- 狗蛋 is studying...
 -- 函数定义1
 function 函数名(参数)
     函数内容
     ...
 end
 
 -- 例如
 function sum( i, j)
   return i + j
 end
 print(sum(10, 23))  -- 函数调用
 
 
 -- 函数定义2
 函数名 = function(参数)
     函数内容
     ...
 end
 
 -- 例如
 sum = function(i, j)
   return i + j
 end
 print(sum(10, 23))  -- 函数调用
 function chenpi()
     print("no return")  -- no return
 end
 
 chenpi()
 
 function chenpi()
     return "one return"
 end
 
 print(chenpi()) -- one return
 
 function chenpi(a, b)
     local x = a + b
     local y = a - b
     return x, y
 end
 
 i, j = chenpi(10, 5)
 print(i)  -- 15
 print(j)  -- 5
 function func()
     local x, y, z = 1, 2, 3
     return x, y, z
 end
 
 print("Hello", "ChenPi", func())      -- Hello   ChenPi  1       2       3    
 print("Hello", func(), "ChenPi")      -- Hello   1       ChenPi
 
 a, b, c, d = 0, func()                -- 0 1 2 3
 
 a, b, c, d = func(), 4                -- 1 4 nil nil
 function 函数名(...)           -- 三个点代表参数个数不确定
 function 函数名(a, b, ...)     -- 2个固定参数,其他参数不确定
 function 函数名(a, ...)        -- 1个固定参数,其他参数不确定
 -- 假设定义如下函数
 function chenpi(a, b, ...)
     print(a)
     print(b)
     print(arg[1])
     print(arg[2])
     print("-------")
 end
     
 chenpi()            -- a=nil,b=nil,arg={}
 chenpi(1)           -- a=1,b=nil,arg={}
 chenpi(1, 2)        -- a=1,b=2,arg={}
 chenpi(1, 2, 3)     -- a=1,b=2,arg={3}
 chenpi(1, 2, 3, 4)  -- a=1,b=2,arg={3,4}
 
 -- 输出结果如下
 nil
 nil
 nil
 nil
 -------
 1
 nil
 nil
 nil
 -------
 1
 2
 nil
 nil
 -------
 1
 2
 3
 nil
 -------
 1
 2
 3
 4
 -------
 -- 以下函数调用耗时比较久
 function func(i)
     while i < 15 do
         i = i + 1
         print(i)
         func(i)
     end
     return i
 end
 
 func(0)
 
 -- 改变顺序,使用尾调函数,执行速度很快(而且1000还比15次数大很多)
 function func(i)
     if i > 1000 then
         return i
     end
         
     i = i + 1
     print(i)
     func(i)  -- func(i) + 1 不算尾调函数
 end
 
 func(0)
table 语句块的结尾一句 函数尾调用 尾调函数

免责声明:文中图文均来自网络,如有侵权请联系删除,心愿游戏发布此文仅为传递信息,不代表心愿游戏认同其观点或证实其描述。

相关文章

更多

精选合集

更多

大家都在玩

热门话题

大家都在看

更多