Lua-编译,执行和错误

目录

一、Lua的"编译":把代码变成可执行的"函数"

1、dofile:简单但不灵活的"一键运行"

2、loadfile:更灵活的"编译后再执行"

3、loadstring:从"字符串"编译代码

4、三者的关系

二、编译的"坑":作用域和性能

1.作用域问题(词法域VS全局编译)

2."函数定义是赋值操作"的误解

[三、更底层的 load 函数(了解即可)](#三、更底层的 load 函数(了解即可))

四、错误处理:让程序更健壮

[1、主动触发错误:error 函数](#1、主动触发错误:error 函数)

[2、简化错误处理:assert 函数](#2、简化错误处理:assert 函数)

3、补充细节


一、Lua的"编译":把代码变成可执行的"函数"

Lua虽然是解释型语言,但它会把源代码预编译成中间形式(可以理解为"可执行的函数"),再执行。这部分核心是三个函数:dofile、loadfile、loadstring。

1、dofile:简单但不灵活的"一键运行"

作用:加载并运行一个Lua文件,相当于"打开文件->编译->执行"一步到位

实例:

Lua 复制代码
dofile("test.lua")--直接运行test.lua中的代码

缺点:如果文件加载失败,会直接报错;并且每次调用都要重新编译,效率不高。

2、loadfile:更灵活的"编译后再执行"

作用:只编译文件,不直接执行,返回一个编译后的函数。用户可以决定什么时候执行这个函数。

实例:

Lua 复制代码
local f = loadfile("test.lua") --编译该文件,返回一个函数
f();  --手动调用编译后的代码
f();  --可以多次调用,不用重复重复编译

优点:

编译一次,可以多次执行;

加载失败时会返回nil+错误信息,方遍自定义错误处理。

3、loadstring:从"字符串"编译代码

作用:和loadfile像似,但是他是从字符串中提取代码并运行,返回一个函数。

实例:

Lua 复制代码
local f = loadstring("print("hello")") --把字符串里面的代码编译
f()  --编译执行分离
4、三者的关系

dofile就是loadfile的简易包装

Lua 复制代码
function dofile(filename)
    local f = assert(loadfile(filename))
    f()
end

二、编译的"坑":作用域和性能

1.作用域问题(词法域VS全局编译)

loadfile编译代码时,不考虑"词法作用域"(即外层函数的局部变量),它编译的代码默认在全局环境中执行。

Lua 复制代码
local i = 0
local f = loadstring("i = i + 1; print(i)")  -- 这里的 i 是全局的 i
local g = function() i = i + 1; print(i) end  -- 这里的 i 是外层的局部 i

f()  --> 1 (修改了全局 i)
g()  --> 2 (修改了外层的局部 i)
2."函数定义是赋值操作"的误解

Lua中加载代码块(如loadfile加载包含函数定义的文件)时,函数定义的本质是"赋值操作",需要手动执行编译后才能完成定义。

Lua 复制代码
--foo.lua文件内容
function foo(x)
    print(x)
end

--main.lua的内容
f = loadfile("foo.lua")
print(foo) -> nil 还未定义
f()
print(foo) -> function的地址,完成了定义
print(foo(999))-> 999 函数可以正常调用

三、更底层的 load 函数(了解即可)

loadfile 和 loadstring 都是基于 load 实现的。load 更灵活,它可以从 "自定义的读取器" 中获取代码(比如分块读取大文件),但平时用得少,知道即可。

四、错误处理:让程序更健壮

1、主动触发错误:error 函数

error 函数的作用是显式地在代码中抛出错误,中断程序执行并提示错误信息。

  • 语法:error(错误消息 [, 错误级别])

  • 示例(用户输入校验): lua

    复制代码
    print("enter a number:")
    n = io.read("*number")  -- 读取数字,若输入非数字则返回 nil
    if not n then
      error("invalid input")  -- 输入无效时,主动抛出错误
    end

    执行后,若输入非数字,程序会中断并提示 invalid input。

2、简化错误处理:assert 函数

assert 是 Lua 内置的 "断言函数",用于简化 "条件不满足则抛错" 的逻辑 ,相当于 if not 条件 then error(消息) end 的简写。

  • 语法:assert(条件, 错误消息)

    • 若 条件 为 true,返回 条件 的值;
    • 若 条件 为 false 或 nil,则抛出 错误消息。
  • 示例(简化上面的输入校验): lua

    复制代码
    print("enter a number:")
    n = assert(io.read("*number"), "invalid input")

    效果和用 error 手动判断完全一致,但代码更简洁。

3、补充细节
  • 错误级别的控制 :error 可选第二个参数控制 "错误在调用栈中的层级",一般用默认值(2)即可,不用额外关注。

  • 与元表的关联 :文末注释提到 "这些操作可通过元表合法化",比如对非 table 进行索引时,若元表定义了 __index,则不会直接报错(后续元表章节会详细讲)。

    -- 捕获 loadstring 的错误
    local f = assert(loadstring("i = i +", "语法错误的代码"))
    -- 如果 loadstring 失败,assert 会抛出清晰的错误

相关推荐
谢亮_vipxieliang11 分钟前
JavaScript this 指向完全指南:调用位置决定一切
开发语言·javascript·ecmascript
denlaku16 分钟前
JDK 13 新特性详解
java·开发语言
念越29 分钟前
题库、练习与错题本代码阅读
开发语言·数据结构
l1t31 分钟前
几种数据库软件count(distinct)和count()from group by子查询性能测试
开发语言·数据库
熊猫钓鱼>_>39 分钟前
大学图论第 6 讲:网络流与二分图匹配——对偶性让瓶颈自己现形
开发语言·算法·面试·职场和发展·图论·校招·面经
方便面不加香菜40 分钟前
C++ 关于多态的知识点讲解
开发语言·c++
jimy11 小时前
C++ 类成员函数的内联定义(inline)详解
开发语言·c++
Nebula_g1 小时前
JavaSE高级:动态代理
java·开发语言·算法·javase
青春逝如流水1 小时前
Java 线程与操作系统、硬件的关系:状态、映射与差异
java·开发语言·多线程·ai文章
谢亮_vipxieliang1 小时前
Go gRPC基础与实战
开发语言·后端·golang