Lua比C / C ++更适合的示例用法

时间:2009-06-02 17:41:26

标签: c++ c lua

我目前正在嵌入Lua并将其用作美化的智能配置文件。但是,我觉得我错过了一些东西,因为人们对Lua的使用赞不绝口。

例如,我可以通过显示这个例子轻松解释为什么你可以使用shell脚本而不是C(诚然,boost regexp是过度杀伤):

#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代码更容易使用它。

EDIT2:

一个例子是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示例的方式不同。

9 个答案:

答案 0 :(得分:10)

使用Lua等脚本语言还有许多其他好处。

Lua与C ++的一些优点:

  • 由于高级性质,开发时间通常较短,如您的示例所示。
  • 不需要重新编译来改变行为。
  • 可以在非开发机器上更改行为。
  • 原型设计非常快速和简单,因为您可以在运行时调整逻辑。

答案 1 :(得分:4)

脚本语言减少了构建复杂GUI所需的工作量,否则需要大量的框架粘合和重复代码。 Lua绑定提供了几个GUI工具包,包括wxWidgetsIUP toolkit

在这两种绑定中,第一类函数值和完全闭包使事件回调易于编码和易于使用。

以Lua为核心的大型应用程序(例如Adobe Photoshop Lightroom)有一个外部C / C ++程序,它承载Lua解释器,并通过向该解释器注册C函数来提供对其核心功能的访问。它通常在C函数中实现计算密集型核心功能,但将整个流程,操作甚至GUI布局留给Lua脚本。

我在自己的项目中发现,当与运行时加载的IUP结合使用时,通常情况下,库存独立Lua解释器(lua.exe或wlua.exe)足以用于外部应用程序基于DLL的自定义Lua模块,用C语言编写,实现需要该级别性能的功能,或通过其他C可调用库实现的功能。

我的项目的重点包括:

  • 真尾调用可以轻松表达有限状态机。
  • 垃圾收集内存管理。
  • 匿名函数,闭包,第一类函数值。
  • 哈希表。
  • 字符串库很丰富。
  • Userdata将垃圾收集器扩展到C端分配。
  • Metatables允许丰富的面向对象和功能技术。
  • 小而功能强大的C API。
  • documentation,以开源作为备份。
  • 通过mailing listwiki
  • 提供良好的用户支持
  • 强大的模块,例如作者和PEG提供的community解析器。

我最喜欢的一个例子是我为嵌入式系统构建的测试夹具,需要大约1000行Lua和1000行C,在lua.exe下运行,并使用IUP呈现完整的Windows GUI。第一个版本在大约一天内运行。在使用MFC的C ++中,它至少需要一周的工作,以及数千行代码。

答案 2 :(得分:3)

尝试用C / C ++实现一个Lua表,你会看到Lua的强大。

在Lua:

a["index"] = "value"

在C中,首先阅读有关链表......

C ++ STL可能会有所帮助,但它会比Lua更加冗长。

,Lua很有吸引力。与C接口非常容易(恕我直言)。

答案 3 :(得分:3)

我不知道我是否为你点击'但是我会尝试。

嵌入Lua的一个优点是,你不仅可以将它用作配置文件,而且实际上可以通过Lua脚本语言提供你的C / C ++ - 接口到lua和'script'它们的用法。

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

突出的用途是游戏逻辑,如AI oder状态机,从变化到游戏的快速往返时间对于开发游戏至关重要。

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

答案 4 :(得分:2)

使用C编程可能是一项非常繁琐且冗余的任务,与更抽象的高级语言相比,这当然适用。

从这个意义上说,你可以比直接在C中完成任务更快地开始和完成事情,这是因为需要在C语言中明确地和手动地设置,完成和清理的许多事情通常都是隐含的。由Lua等脚本语言自动处理(例如想象内存管理)。

同样,许多更抽象的数据结构和算法通常由这种高级语言直接提供,因此如果您只需要一个标准容器,就不必重新发明轮子并重新实现它(想想链表,树,地图等)。

因此,当使用相当抽象的脚本语言(如Lua甚至Python)时,您可以获得相当好的ROI,特别是如果相应的语言带有良好的核心功能库。

因此,脚本编写实际上是理想的想法和项目的原型,因为那时您需要能够专注于您的工作,而不是大多数项目可能相同的所有机械冗余。

完成基本原型后,您可以随时了解如何进一步改进和优化它,可能是在C空间中重新实现基本的关键功能,以提高运行时性能。

答案 5 :(得分:1)

有关Lua更适合的示例,那么c ++会考虑分发脚本。 Mush Client提供Lua作为脚本语言。如上面的链接所示,你可以用Lua做很多事情来扩展程序。与C ++不同,虽然Lua不需要编译并且可以被限制。例如,您可以沙箱Lua,因此无法访问文件系统。这意味着如果你从别人那里得到一个脚本,它就无法破坏你的数据,因为它无法写入磁盘。

答案 6 :(得分:1)

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 is the key word in which the search string occurs
  -- pos is its position in the document
  -- lw is the width of the context around the word
  -- start is the position of the search string within the word
  local shift = (start or 1) - 1  -- number of cols to shift word to align keys
  lw = lw - shift -- 'left width'
  local rw = cols - 20 - 3 - lw - string.len(words[pos])  -- right width
  local data = assert(map:lookup(pos)[1], "no map info for position")
     -- data == source of this word
  local function range(lo, hi)
    -- return words in the range lo..hi, but only in the current section
    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
  -- grab words on left and right, 
  -- then format and print as many as we have room for
  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

答案 7 :(得分:1)

我使用一个名为Love2D的游戏引擎,它使用Lua编写游戏。所有的系统调用和繁重工作都是在一个读取Lua脚本的C程序中完成的。

使用C或C ++编写游戏时,您会发现自己正在尝试使用系统的细微之处,而不仅仅是实现您的想法。

Lua允许“干净”的脏样编码。

这是一个用纯lua编写的游戏对象的例子:

local GameObj = {}              -- {} is an empty table
GameObj.position = {x=0,y=0}
GameObj.components = {}

function GameObject:update()
    for i,v in ipairs(self.components) do    -- For each component...
        v:update(self)                       -- call the update method
    end
end

要实例化:

myObj = setmetatable({},{__index=GameObj})
-- tables can have a meta table which define certain behaviours
-- __index defines a table that is referred to when the table
-- itself doesn't have the requested index

让我们定义一个组件,键盘控制怎么样? 假设我们有一个为我们输入的对象(将提供C端)

KeyBoardControl = {}
function KeyBoardControl:update(caller)
    -- assuming "Input", an object that has a isKeyDown function that returns
    -- a boolean
    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
--Instantiate a new KeyboardControl and add it to our components
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编程,匿名函数以及其他通常让comp-sci老师微笑的东西。

答案 8 :(得分:1)

LUA有closures,关闭摇滚。对于example

function newCounter ()
  local i = 0
  return function ()   -- anonymous function
           i = i + 1
           return i
         end
end

c1 = newCounter()
print(c1())  --> 1
print(c1())  --> 2

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