Пример использования, где Lua подходит намного лучше, чем C/С++

В настоящее время я внедряю Lua и использую его в качестве прославленного интеллектуального конфигурационного файла. Тем не менее, я думаю, что у меня что-то не хватает, потому что люди бредит об использовании Lua.

Например, я могу легко объяснить, почему вы можете использовать сценарий оболочки вместо 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, которые могут сделать это 'click' для меня?

EDIT: Может быть, моя проблема в том, что я не знаю Lua достаточно хорошо, чтобы использовать ее свободно, поскольку мне легче писать код C.

EDIT2:

Одним из примеров является игрушечная факториальная программа в С++ и 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.

Ответы

Ответ 1

Использование языка сценариев, такого как Lua, имеет много других преимуществ.

Пара преимуществ Lua против С++:

  • Он часто короче с точки зрения времени разработки из-за высокого уровня, как в вашем примере.
  • Это не требует перекомпиляции для изменения поведения.
  • Поведение может быть изменено на машинах без разработки.
  • Прототипирование очень быстро и просто, поскольку вы можете просто настроить логику во время выполнения.

Ответ 2

Языки сценариев уменьшают усилия, необходимые для создания сложных графических интерфейсов, которые в противном случае требуют много каркасного клея и повторения кода. Несколько инструментов GUI доступны с привязками Lua, включая wxWidgets и IUP инструментарий.

В обоих этих привязках значения функции первого класса и полные блокировки делают обратные вызовы событий легко кодируемыми и простыми в использовании.

Большое приложение, использующее Lua в своем ядре (например, Adobe Photoshop Lightroom), имеет внешнюю программу C/С++, на которой размещен интерпретатор Lua, и предоставляет доступ к его основным функциям, регистрируя функции C с этим интерпретатором. Обычно он реализует основные функции, связанные с вычислением, в функциях C, но оставляет общий поток, работу и даже макет графического интерфейса для сценариев Lua.

В моих собственных проектах я обнаружил, что часто бывает, что автономный интерпретатор Lua (lua.exe или wlua.exe) достаточно для внешнего приложения в сочетании с IUP, загруженным во время выполнения, с одним или двумя пользовательские DLL-модули Lua, закодированные в C, которые реализуют функции, требующие такого уровня производительности, или функции, которые реализуются через другие библиотеки C-callable.

Важные моменты для моих проектов включают:

  • Истинные хвостовые вызовы позволяют легко выражать конечные конечные машины.
  • Управление памятью, собранной с помощью мусора.
  • Анонимные функции, замыкания, значения функций первого класса.
  • Хэш-таблицы.
  • Богатая библиотека строк.
  • Userdata расширяет сборщик мусора до распределения сторон C.
  • Metatables позволяют использовать разнообразные объектно-ориентированные и функциональные методы.
  • Небольшой, но достаточно мощный API C.
  • Хорошая документация с открытым исходным кодом в качестве резервной копии.
  • Хороший пользователь для поддержки пользователей через список рассылки и wiki.
  • Мощные модули, такие как PEG парсер, доступный от авторов и .

Один из моих любимых примеров для цитирования - это тестовое устройство, которое я построил для встроенной системы, которая требовала около 1000 строк Lua и 1000 строк C, работала под lua.exe и использовала IUP для представления полного графического интерфейса Windows. Первая версия работала примерно через день. В С++ с MFC это было бы, по крайней мере, неделю работы и много тысяч строк кода.

Ответ 3

Попробуйте реализовать таблицу Lua в C/С++, вы увидите силу Lua прямо там.

В Lua:

a["index"] = "value"

В C начните с чтения связанного списка...

С++ STL может помочь, но он будет намного более подробным, чем Lua.

Также, Lua делает отличный клей. Это так просто (IMHO), чтобы взаимодействовать с C.

Ответ 4

Я не знаю, сделаю ли это 'click' для вас, но я попробую.

Одним из преимуществ встраивания Lua является то, что вы можете не только использовать его в качестве файла конфигурации, но и фактически предлагать свои C/С++-интерфейсы для lua и 'script' их использования с помощью языка Lua-скриптов.

Если вы хотите изменить поведение/логику своего приложения, вам просто нужно изменить код в Lua- script без необходимости перекомпилировать все приложение.

Известные применения - это логические игры, такие как компьютерные автоматы, в которых быстрый переход от игры к игре необходим для разработки игры.

Конечно, основная логика тогда должна присутствовать в Lua- script, а не внутри C/С++-кода, чтобы эффективно использоваться.

Ответ 5

Программирование только на C может быть очень утомительной и избыточной задачей, это, безусловно, применимо по сравнению с более абстрактными языками высокого уровня.

В этом смысле вы можете начать работу и закончить работу гораздо быстрее, чем делать все непосредственно на C, потому что многие вещи, которые нужно настраивать, делать и очищать явно и вручную на C, часто неявно и автоматически обрабатывается языком сценариев, таким как Lua (например, представьте себе управление памятью).

Аналогичным образом, многие более абстрактные структуры данных и алгоритмы часто напрямую предоставляются такими языками высокого уровня, поэтому вам не нужно повторно изобретать колесо и повторно выполнять его, если все, что вам нужно, это стандартный контейнер (подумайте связанный список, дерево, карта и т.д.).

Таким образом, вы можете получить довольно хороший ROI при использовании довольно абстрактного языка сценариев, такого как Lua или даже Python, особенно если соответствующий язык имеет хорошую библиотеку основных функций.

Итак, сценарии на самом деле идеальны для прототипа идей и проектов, потому что когда вам нужно сосредоточиться на своих усилиях, а не на всех механических избыточности, которые, вероятно, будут одинаковыми для большинства проектов.

После того, как вы создали базовый прототип, вы всегда можете увидеть, как улучшить и оптимизировать его дальше, возможно, повторно внедрить основные функциональные возможности в пространстве C, чтобы улучшить производительность выполнения.

Ответ 6

В качестве примера, где Lua подходит лучше, тогда С++ рассмотрит распространение скриптов. Клиент Mush предлагает Lua как язык сценариев. Как показано в приведенной выше ссылке, вы можете много сделать с Lua для расширения программы. В отличие от С++, хотя Lua не нужно компилировать и может быть ограничено. Например, вы можете использовать песочницу Lua, чтобы она не могла получить доступ к файловой системе. Это означает, что если вы получите script от кого-то другого, он не сможет уничтожить ваши данные, так как он не может записать на диск.

Ответ 7

Основными преимуществами Lua как языка программирования (помимо встраивания) являются

  • Мощная, эффективная хеш-таблица в качестве основной структуры данных
  • Библиотека строковой обработки с отличным балансом сложности и выразительной мощности.
  • Первоклассные функции и общий цикл for
  • Автоматическое управление памятью.

Трудно найти краткий пример, иллюстрирующий все это. У меня есть 191 сценарий Lua в моем каталоге ~/bin; здесь, который выводит результат 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

Ответ 8

Я использую движок игры Love2D, который использует Lua для написания игр. Все системные вызовы и тяжелая атлетика выполняются в программе на C, которая читает Lua script.

Написание игры на 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-side)

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(), он проверяет ввод и перемещает его

Скажем, мы будем использовать много таких игр GameObj с KeyboardControl, мы можем создать прототип KeyObj и использовать THAT как унаследованный объект:

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 есть несколько приятных других функций, таких как функции типа первоклассного типа, позволяющие программировать лямбда, анонимные функции и другие вещи, которые, как правило, улыбаются учителям comp-sci.

Ответ 9

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

Вы можете создать функцию и передать ее. Иногда это более удобно, чем создавать отдельный класс и создавать его.