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

点赞
stackoverflow用户65358
stackoverflow用户65358

使用诸如Lua等脚本语言具有许多其他优势。

Lua与C ++相比的几个优点:

  • 由于高级性质,它通常在开发时间方面更短,例如您的示例。
  • 它不需要重新编译以更改行为。
  • 可以在非开发机器上更改行为。
  • 由于可以在运行时轻松调整逻辑,因此原型设计非常快速简便。
2009-06-02 17:45:27
stackoverflow用户101616
stackoverflow用户101616

尝试在C/C++中实现Lua表格,你会发现Lua的强大之处。

在Lua中:

a["index"] = "value"

在C中,首先要学习链表的相关知识……

C++ STL可以帮忙,但它比Lua要更冗长。

另外,Lua非常适合作为粘合剂。我认为它很容易与C进行接口。

2009-06-02 17:46:13
stackoverflow用户57601
stackoverflow用户57601

我不知道我能否让你理解,但我会尝试。

嵌入Lua的优势之一是,你不仅可以将其用作配置文件,而且可以通过Lua脚本语言提供你的C/C++接口并“脚本”它们的使用。

如果你想改变应用程序的行为/逻辑,只需改变Lua脚本中的代码,无需重新编译整个应用程序。

常见的用途是游戏逻辑,如AI或状态机,其中从更改到播放的快速往返时间对于开发游戏至关重要。

当然,主要逻辑必须在Lua脚本中存在,而不是在C/C++代码中,才能有效地使用。

2009-06-02 17:47:45
stackoverflow用户14744
stackoverflow用户14744

Lua 相比 C++ 更适合分发脚本示例

以分发脚本为例,Mush Client 提供了 Lua 作为脚本语言。如上所示的链接,你可以使用 Lua 来扩展程序的功能。但与 C++ 不同,Lua 无需编译,也可以进行限制。例如,你可以将 Lua 约束在一个沙盒中,以避免其访问文件系统。这意味着,如果你从别人那里得到一个脚本,它是无法破坏你的数据,因为它无法写入到磁盘中。

2009-06-02 18:10:07
stackoverflow用户78244
stackoverflow用户78244

在纯C语言编程可能会是一项非常枯燥和冗长的任务,尤其是与更抽象、高级的语言相比较时。

因此,通过使用脚本语言如Lua(例如,想象一下内存管理)进行许多需要在C语言中显式手动设置、完成和清理的工作时,您可以更快地开始和完成任务。同样,许多更抽象的数据结构和算法通常由这种高级语言直接提供,因此,如果您只需要一个标准容器(如链表、树、映射等),那么您就不必重新发明轮子并重新实现它。

因此,特别是如果相应的语言提供了良好的核心功能库,那么使用相当抽象的脚本语言(如Lua甚至Python)可以获得相当不错的投资回报。

因此,编写脚本非常适合原型设计和项目,因为在这些情况下,您需要集中精力进行努力,而不必处理大多数项目中相同的机械冗余。

完成基本原型后,您始终可以查看如何进一步改进和优化它,可能通过在C空间中重新实现关键功能来改善运行时性能。

2009-06-02 19:37:43
stackoverflow用户41661
stackoverflow用户41661

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
2009-06-04 03:45:10
stackoverflow用户68204
stackoverflow用户68204

脚本语言降低了构建复杂 GUI 的难度,这些 GUI 否则需要大量的框架粘合和代码重复。多个 GUI 工具包都具有 Lua 绑定,包括 wxWidgetsIUP 工具包

在这两个绑定中,一流的函数值和完整的闭包使得事件回调很容易编写和使用。

一个以 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 中,这至少需要一周的工作,并且需要成千上万行的代码。

2009-06-05 01:13:20
stackoverflow用户1727123
stackoverflow用户1727123

我使用一个名为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编程、匿名函数和其他通常使计算机科学老师面露怪异微笑的东西。

2013-05-07 12:13:47
stackoverflow用户497208
stackoverflow用户497208

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

你可以创建一个函数并将其传递。有时候比创建单独的类并实例化它更方便。

2013-07-09 20:46:48