17

我目前正在嵌入 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 代码更容易。

编辑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;
}

卢阿:

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 示例不同。

4

9 回答 9

13

使用像 Lua 这样的脚本语言还有很多其他的好处。

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

  • 由于高级特性,开发时间通常更短,如您的示例所示。
  • 它不需要重新编译来改变行为。
  • 可以在非开发机器上更改行为。
  • 原型制作非常快速和简单,因为您可以在运行时调整逻辑。
于 2009-06-02T17:45:27.670 回答
5

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

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

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

我在自己的项目中发现,当与在运行时加载的 IUP 以及一个或两个自定义 DLL 结合使用时,通常的独立 Lua 解释器(lua.exe 或 wlua.exe)对于外部应用程序来说已经足够了——基于 Lua 模块,用 C 编码,实现需要该级别性能的功能,或通过其他 C 可调用库实现的功能。

我的项目的要点包括:

  • 真正的尾调用允许简单地表达有限状态机。
  • 垃圾收集内存管理。
  • 匿名函数、闭包、第一类函数值。
  • 哈希表。
  • 足够丰富的字符串库。
  • Userdata 将垃圾收集器扩展到 C 端分配。
  • 元表允许丰富多样的面向对象和函数式技术。
  • 小但足够强大的 C API。
  • 良好的文档,以开源作为备份。
  • 通过邮件列表wiki提供良好的用户对用户支持。
  • 强大的模块,例如作者和社区提供的PEG解析器。

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

于 2009-06-05T01:13:20.290 回答
3

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

在 Lua 中:

a["index"] = "value"

在 C 语言中,首先阅读链表...

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

此外,Lua 可以制作很好的胶水。与 C 接口非常容易(恕我直言)。

于 2009-06-02T17:46:13.923 回答
3

我不知道我是否会为您“点击”,但我会尝试。

嵌入 Lua 的优点之一是,您不仅可以将其用作配置文件,而且实际上可以为 lua 提供 C/C++ 接口,并通过 Lua 脚本语言“编写”它们的使用。

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

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

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

于 2009-06-02T17:47:45.217 回答
2

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

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

类似地,更多抽象的数据结构和算法通常由此类高级语言直接提供,因此如果您只需要一个标准容器(想想链表,树,地图等)。

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

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

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

于 2009-06-02T19:37:43.857 回答
2

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-09T20:46:48.730 回答
1

For an example of where Lua fits better then c++ look at distributing scripts. Mush Client offers Lua as a scripting language. As shown by the link above you can do a lot with Lua to extend the program. Unlike C++ though Lua doesn't have to be compiled and can be restricted. For example you can sandbox Lua so it can't access the file system. This means that if you get a script from someone else it is incapable of destroying your data since it can't write to the disk.

于 2009-06-02T18:10:07.097 回答
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 老师笑得令人毛骨悚然的东西。

于 2013-05-07T12:13:47.177 回答
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

这个例子展示了几个优点,但对表格没有任何意义。

下面是 Key Word In Context 索引程序的一个简短片段,它从表中获取上下文并在上下文中格式化关键字。这个例子更广泛地使用了嵌套函数,并展示了更多的表格和字符串内容:

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
于 2009-06-04T03:45:10.943 回答