Lua比C/C++更适用的示例用法
我目前正在嵌入Lua并将其用作智能化配置文件。然而,我觉得我错过了一些东西,因为人们对Lua的用途赞不绝口。
例如,我可以通过展示这个例子(虽然有些浮夸,但使用boost regexp好处更明显)来轻松解释为什么您可能会使用shell脚本而不是C:
#include <dirent.h>
#include <stdio.h>
#include <boost/regex.hpp>
int main(int argc, char * argv[]) {
DIR *d;
struct dirent *dir;
boost::regex re(".*\\.cpp$");
if (argc==2) d = opendir(argv[1]); else d = opendir(".");
if (d) {
while ((dir = readdir(d)) != NULL) {
if (boost::regex_match(dir->d_name, re)) printf("%s\n", dir->d_name);
}
closedir(d);
}
return(0);
与之比较:
for foo in *.cpp; do echo $foo; done;
你有没有什么可以用Lua来让我“明白”的例子?
编辑:也许我的问题是我还不够熟练地使用Lua,所以我发现写C代码更容易。
编辑2:
一个例子是C++和Lua中的玩具阶乘程序:
#include <iostream>
int fact (int n){
if (n==0) return 1; else
return (n*fact(n-1));
}
int main (){
int input;
using namespace std;
cout << "Enter a number: " ;
cin >> input;
cout << "factorial: " << fact(input) << endl;
return 0;
}
Lua:
function fact (n)
if n==0 then
return 1
else
return n * (fact(n-1))
end
end
print ("enter a number")
a = io.read("*number")
print ("Factorial: ",fact(a))
在这里,程序看起来很相似,但显然有一些可以消除的include、namespace和main()声明中的瑕疵。还可以删除变量声明和强类型。
现在人们说这是添加到更大程序中的优势,还是还有更多内容?这并不像bash示例那样突出。
原文链接 https://stackoverflow.com/questions/940896
尝试在C/C++中实现Lua表格,你会发现Lua的强大之处。
在Lua中:
a["index"] = "value"
在C中,首先要学习链表的相关知识……
C++ STL可以帮忙,但它比Lua要更冗长。
另外,Lua非常适合作为粘合剂。我认为它很容易与C进行接口。
我不知道我能否让你理解,但我会尝试。
嵌入Lua的优势之一是,你不仅可以将其用作配置文件,而且可以通过Lua脚本语言提供你的C/C++接口并“脚本”它们的使用。
如果你想改变应用程序的行为/逻辑,只需改变Lua脚本中的代码,无需重新编译整个应用程序。
常见的用途是游戏逻辑,如AI或状态机,其中从更改到播放的快速往返时间对于开发游戏至关重要。
当然,主要逻辑必须在Lua脚本中存在,而不是在C/C++代码中,才能有效地使用。
Lua 相比 C++ 更适合分发脚本示例
以分发脚本为例,Mush Client 提供了 Lua 作为脚本语言。如上所示的链接,你可以使用 Lua 来扩展程序的功能。但与 C++ 不同,Lua 无需编译,也可以进行限制。例如,你可以将 Lua 约束在一个沙盒中,以避免其访问文件系统。这意味着,如果你从别人那里得到一个脚本,它是无法破坏你的数据,因为它无法写入到磁盘中。
在纯C语言编程可能会是一项非常枯燥和冗长的任务,尤其是与更抽象、高级的语言相比较时。
因此,通过使用脚本语言如Lua(例如,想象一下内存管理)进行许多需要在C语言中显式手动设置、完成和清理的工作时,您可以更快地开始和完成任务。同样,许多更抽象的数据结构和算法通常由这种高级语言直接提供,因此,如果您只需要一个标准容器(如链表、树、映射等),那么您就不必重新发明轮子并重新实现它。
因此,特别是如果相应的语言提供了良好的核心功能库,那么使用相当抽象的脚本语言(如Lua甚至Python)可以获得相当不错的投资回报。
因此,编写脚本非常适合原型设计和项目,因为在这些情况下,您需要集中精力进行努力,而不必处理大多数项目中相同的机械冗余。
完成基本原型后,您始终可以查看如何进一步改进和优化它,可能通过在C空间中重新实现关键功能来改善运行时性能。
Lua 作为一种编程语言的主要优点(除了可嵌入性)有:
- 以强大、高效的哈希表作为主要数据结构
- 带有很好的复杂性和表现力平衡的字符串处理库
- 一流函数和通用的
for
循环 - 自动内存管理!!
很难找到一个简短的示例,可以说明所有这些。我在 ~/bin
目录中有191个Lua脚本,这是一个将“pstotext”的输出合并为以连字符结尾的行的示例:
local function printf(...) return io.stdout:write(string.format(...)) end
local function eprintf(...) return io.stderr:write(string.format(...)) end
local strfind, strlen = string.find, string.len
function joined_lines(f)
return coroutine.wrap(function()
local s = ''
for l in f:lines() do
s = s .. l
local n = strlen(s)
if strfind(s, '[%-\173]$', n-1) then
s = string.sub(s, 1, n-1)
else
coroutine.yield(s)
s = ''
end
end
end)
end
-- printf('hyphen is %q; index is %d\n', 'Â', string.byte('Â'))
for _, f in ipairs(arg) do
for l in joined_lines(io.popen('pstotext ' .. f, 'r')) do
printf('%s\n', l)
end
end
这个示例显示了几个特点,但并没有在表格方面做出任何有趣的事情。
以下是一个关键词上下文索引程序的短片段,它从一张表中获取上下文并格式化关键词上下文。这个示例更广泛地使用了嵌套函数,并展示了一些更多的表格和字符串内容:
local function showpos(word, pos, lw, start)
-- word是搜索字符串出现的关键词,pos是它在文档中的位置,lw是单词周围上下文的宽度,start是搜索字符串在单词中的位置
local shift = (start or 1) - 1 -- 将关键字移动以对齐键
lw = lw - shift -- 左宽
local rw = cols - 20 - 3 - lw - string.len(words[pos]) -- 右宽
local data = assert(map:lookup(pos)[1], "no map info for position")
-- data == 此单词的来源
local function range(lo, hi)
-- 返回lo..hi范围内的单词,但仅在当前部分中
if lo < data.lo then lo = data.lo end
if hi > data.hi then hi = data.hi end
local t = { }
for i = lo, hi-1 do table.insert(t, words[i]) end
return table.concat(t, ' ')
end
-- 获取左右单词,然后格式化并打印我们有空间的尽可能多的单词。
local left = range(pos-width, pos)
local right = range(pos+1, pos+1+width)
local fmt = string.format('[%%-18.18s] %%%d.%ds %%s %%-%d.%ds\n',
lw, lw, rw, rw)
printf(fmt, data.title, string.sub(left, -lw), word, right)
end
脚本语言降低了构建复杂 GUI 的难度,这些 GUI 否则需要大量的框架粘合和代码重复。多个 GUI 工具包都具有 Lua 绑定,包括 wxWidgets 和 IUP 工具包。
在这两个绑定中,一流的函数值和完整的闭包使得事件回调很容易编写和使用。
一个以 Lua 为核心的大型应用程序(如 Adobe Photoshop Lightroom)有一个外部的 C/C++ 程序,它主持 Lua 解释器并通过向解释器注册 C 函数提供对其核心功能的访问。它通常将计算密集型的核心函数实现为 C 函数,但将整体流程、操作甚至 GUI 布局都留给 Lua 脚本。
在我的项目中,我发现在运行时加载 IUP 并与一两个自定义的基于 DLL 编写的 Lua 模块相结合时,原始独立 Lua 解释器(lua.exe 或 wlua.exe)在外部应用程序中通常是足够的,这些模块实现了需要该级别性能或通过其他 C-callable 库实现的特性。
对于我的项目,重要的点包括:
- 真实的尾调用允许轻松表达有限状态机。
- 回收垃圾内存管理。
- 匿名函数、闭包、一流的函数值。
- 散列表。
- 足够丰富的字符串库。
- 使用户数据扩展到 C 侧分配的垃圾收集器。
- 元表允许各种富有变化的面向对象和函数技术。
- 小但功能强大的 C API。
- 良好的文档,备份为开源。
- 通过邮件列表和维基提供的好的用户支持。
- 强大的模块,如PEG解析器,作者和社区都提供。
我最喜欢引用的一个示例是我为一个嵌入式系统建立的测试夹具,需要大约 1000 行 Lua 和 1000 行 C,在 lua.exe 下运行,并使用 IUP 提供完整的 Windows GUI。第一个版本大约在一天内完成。在 C++ 和 MFC 中,这至少需要一周的工作,并且需要成千上万行的代码。
我使用一个名为Love2D的游戏引擎,使用Lua编写游戏。所有系统调用和重型工作都是在一个C程序中完成的,该程序读取Lua脚本。
使用C或C++编写游戏时,你会发现自己尝试处理系统的微妙之处,而不仅仅是实现你的想法。
Lua允许进行“干净”的混合编程风格。
下面是一个纯Lua编写的游戏对象的示例:
local GameObj = {} -- {} 是一个空表
GameObj.position = {x=0,y=0}
GameObj.components = {}
function GameObject:update()
for i,v in ipairs(self.components) do -- 对于每个组件…
v:update(self) -- 调用更新方法
end
end
要实例化:
myObj = setmetatable({},{__index=GameObj})
-- 表可以有一个元表,其中定义了某些行为
-- __index 定义了一个当表本身没有被索引到时所引用的表
接下来,我们定义组件,比如键盘控制?
假设我们有一个为我们输入执行的对象(它将从C侧提供):
KeyBoardControl = {}
function KeyBoardControl:update(caller)
-- 假设“Input”是一个具有isKeyDown函数的对象,该函数返回布尔值
if Input.isKeyDown("left") then
caller.position.x = caller.position.x-1
end
if Input.isKeyDown("right") then
caller.position.x = caller.position.x+1
end
if Input.isKeyDown("up") then
caller.position.y = caller.position.y-1
end
if Input.isKeyDown("down") then
caller.position.y = caller.position.y+1
end
end
-- 实例化一个新的KeyboardControl并将其添加到我们的组件中
table.insert(myObj.components,setmetatable({},{__index=KeyboardControl})
现在,当我们调用myObj:update()时,它将检查输入并移动它。
假设我们将使用大量这种带有KeyboardControl的GameObj,我们可以实例化一个原型KeyObj并像继承的对象一样使用它:
KeyObj = setmetatable( {}, {__index = GameObj} )
table.insert(KeyObj.components,setmetatable( {}, {__index = KeyboardControl} )
myKeyObjs = {}
for i=1,10 do
myKeyObjs[i] = setmetatable( {}, {__index = KeyObj} )
end
现在,我们有一个KeyObj表可以玩耍。
在这里,我们可以看到Lua为我们提供了一个强大、易于扩展、灵活的对象系统,它允许我们根据我们要解决的问题结构化我们的程序,而不是弯曲问题来适应我们的语言。
此外,Lua还具有一些不错的功能,如函数作为第一类类型,允许使用lambda编程、匿名函数和其他通常使计算机科学老师面露怪异微笑的东西。
LUA有闭包,并且闭包很棒。例如:
function newCounter ()
local i = 0
return function () -- anonymous function
i = i + 1
return i
end
end
c1 = newCounter()
print(c1()) --> 1
print(c1()) --> 2
你可以创建一个函数并将其传递。有时候比创建单独的类并实例化它更方便。
- 如何在roblox studio中1:1导入真实世界的地形?
- 求解,lua_resume的第二次调用继续执行协程问题。
- 【上海普陀区】内向猫网络招募【Skynet游戏框架Lua后端程序员】
- SF爱好求教:如何用lua实现游戏内调用数据库函数实现账号密码注册?
- Lua实现网站后台开发
- LUA错误显式返回,社区常见的规约是怎么样的
- lua5.3下载库失败
- 请问如何实现文本框内容和某个网页搜索框内容连接,并把网页输出来的结果反馈到另外一个文本框上
- lua lanes多线程使用
- 一个kv数据库
- openresty 有没有比较轻量的 docker 镜像
- 想问一下,有大佬用过luacurl吗
- 在Lua执行过程中使用Load函数出现问题
- 为什么 neovim 里没有显示一些特殊字符?
- Lua比较两个表的值(不考虑键的顺序)
- 有个lua简单的项目,外包,有意者加微信 liuheng600456详谈,最好在成都
- 如何在 Visual Studio 2022 中运行 Lua 代码?
- addEventListener 返回 nil Lua
- Lua中获取用户配置主目录的跨平台方法
- 如何编写 Lua 模式将字符串(嵌套数组)转换为真正的数组?
使用诸如Lua等脚本语言具有许多其他优势。
Lua与C ++相比的几个优点: