NetSago
Вход
Войти

Как присоединиться?
Меню
Главная
События
Заметки
 Статьи
Теги
Поиск
О Проекте
Ссылки
Наше
RSS События по RSS
RSS Заметки по RSS
netsago NetSago
Популярное
Руководство по получению прибыли от Свободных и Открытых Проектов by Джон Эндрюс

Восстановление удаленных текстовых файлов в ФС ext3 by scamelscrud

Статьи — Введение в Lua
СтатьиПрограммирование

Введение в Lua
Keith Fieldhouse
14 февраля 2008 12:32



Теги: lua, programming

Версия для печати (откроется в новом окне)


Оригинал материала

Нет причин считать, что только веб-разработчикам может доставаться все самое интересное. Web 2.0 API сделали пленительным сотрудничество между разработчиками и обширным сообществом разработчиков-пользователей.

Конечно же, расширяемость — далеко не новая идея. Во многих приложениях есть дополнительные фреймворки (например, Photoshop), или язык расширений (например, Emacs). А что если можно легко встроить полностью динамический язык с традиционным синтаксисом, в то время, как размер вашего приложения увеличится всего на 200 Кб на платформе x86? Это можно сделать с Lua!


Начальные сведения о Lua.

Разработкой Lua руководит Roberto Ierusalimschy из Папского Католического Университета Рио-де-Жанейро в Бразилии. Последняя версия (5.1.2) доступна под лицензией MIT. Lua на 99% написана на ANSI C. Это главная цель разработки — сделать Lua компактным, эффективным и простым для интеграции в другие C/C++ программы. Разработчики игр (таких как World of Warcraft, разрабатываемой Blizzard Entertainment) в большой мере используют Lua как язык расширений и конфигурации.

Буквально каждый человек, хоть с каким-нибудь опытом программирования, должен найти синтаксис Lua лаконичным и легким для чтения. Комментарии вносятся с помощью двух дефисов. Высказывание end ограничивает управляющие структуры (if, for, while). Все переменные являются глобальные, кроме объявленных с помощью local. Фундаментальные типы данных в Lua включают в себя числа (представленные типом double), строки и булевы константы. В Lua есть ключевые слова true и false. Любое выражение, не вычисляющееся как nil, является true. Запомните, что 0 и арифметическое выражение, результатом которого является 0 — это не nil. Таким образом, Lua принимает их, как true, когда вы их используете в условиях.

Наконец, Lua поддерживает userdata как один из фундаментальных типов данных. По определению, userdata может принимать значение ANSI C указателя, что полезно при передаче ссылок через границу между C и Lua, и наоборот.

Несмотря на маленький размер интерпретатора Lua, сам язык довольно богатый.

Единственная встроенная структура данных в Lua — это таблица. Для программистов на Perl это хеш, программисты Python легко узнают словарь. Вот несколько примеров использования таблиц в Lua:

     a = {} -- Инициализирует пустую таблицу
a[1] = "Fred" -- Определяет "Fred" на место, 
              -- индексируемое номером 1
a["1"] = 7 -- Определяет цифру 7 на место, 
           -- индексируемое строкой "1"


Любой тип данных в Lua может быть индексом таблицы, создание таблиц — очень мощный инструмент. Lua расширяет возможности таблиц, предоставляя разные синтаксические стили для их объявления. Стандартный конструктор таблицы выглядит вот так:
t = { "Name"="Keith", "Address"="Ballston Lake, New York"}

Конструктор, написанный так:
t2 = { "First", "Second","Third"}

эквивалентен такому:
t3 = { [1]="First", [2]="Second", [3]="Third" }

Последний способ инициализации таблицы, позволяет работать с ней, как с массивом. Стоить заметить, что в этом случае первым индексом будет 1, а не 0, как во многих других языках.

Следующие две формы доступа к таблице эквиваленты в случае строковых ключей:
t3["Name"] = "Keith"
t3.Name    = "Keith"

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


Вариации на тему.

Следующие варианты священной программы «Hello World» иллюстрируют гибкую и расширяемую природу языка. Для начала, простейшая реализация:
print("Hello World")

А вот объявление функции, которая принимает в качестве параметра имя персоны, которую надо поприветствовать. Оператор «две точки» является конкатенацией строк:
sayhello = function(person) 
    print("Hello "..person)
end

Вы можете определять функции, как переменные, передавать их в качестве параметров в другие функции, помещать их в таблицы и, в общем-то, делать с ними все, что и с любой другой величиной в Lua. У функций в Lua нет имен. Вместо этого, когда вам надо вызвать функцию, вы используете оператор () к переменным, содержащим определение функции. Выполнение функции, содержащейся в таблице, делается так:
t = {}
function t.sayhello(name)
    print (Hello..name)
end

t.sayhello("Fred")

Это очень похоже на вызов метода, кроме того, что здесь нет ссылок self или this для доступа к функциям. В Lua это реализовано добавлением оператора : (двоеточие). Ссылаясь на элемент таблицы с помощью : вместо ., автоматически позволяет Lua допустить self параметр в функции. Вот так:
t      = {}
t.Name = Fred

function t:sayhello()
   print (Hello..self.Name)
end

t:sayhello()
-- Или два других, равнозначных выражения:
t.sayhello(t)
t['sayhello'](t)

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

Lua использует мощную концепцию таблиц метаданных, что, помимо всего прочего, помогает ему преодолеть окончательный отрыв от объектно-ориентированного программирования (по-прежнему без замены VM). Таблица метаданных это обычная таблица в Lua, которая присоединена к данной таблице с помощью встроенной функции setmetatable. Lua использует таблицы метаданных для нескольких специальных функций контроля работы связанных таблиц.

В таблице метаданных могут содержаться несколько специальных записей. Например, самая важная из них это __index. Эта запись содержит таблицу или функцию, к которой Lua обратится если в связанной с ней таблице не найдется запрашиваемая запись. Рассмотрим таблицу метаданных М, чья запись __index содержит таблицу Р. Если М таблица метаданных для таблицы Т, и любой код запросит несуществующую запись в таблице Т, то Lua обратится к таблице Р на предмет существования запрашиваемой записи. Конечно же, Р может иметь свою собственную таблицу метаданных. Также, таблица может быть своей собственной таблицей метаданных – в этом случае записи, такие как __index будут в таблице, и будут отображаться, например, в её итераторах, но вести себя также.

Учитывая это, программист на Lua может использовать некоторые приемы объектно-ориентированного программирования, создавая «экземпляры» объекта Hello. Базовый объект выглядит так:
Hello = {}
function Hello:sayhello()
    print("Hello "..self.Name)
end

Добавляем конструктор New с помощью следующего кода:
function Hello:New(name)
    -- Создать новый, очистить 
    -- таблицу как в экземпляре объекта Hello
    local instance = {}

    -- Инициализируем член Name
    instance.Name  = name

    -- Определяем объект Hello как таблицу метаданных
    -- и таблицу __index экземпляра.  В этом случае 
    -- объект Hello ищет любого не найденного члена
    -- (метода)
    setmetatable(instance,self)
    self.__index   = self

    -- Возвращаем экземпляр 
    return instance
end

fred = Hello:New("Fred");
fred:sayhello()

В этом конструкторе, таблица Hello является также таблицей метаданных и таблицей __index экземпляра объекта. Даже если в таблице экземпляра нет, например, функции sayhello, Lua может найти её через взаимодействие с записью __index таблицы метаданных. Знатоки объектно-ориентированного программирования узнают в этом систему, основанную на прототипах объекта, схожую с теми, что имеют языки Self и JavaScript.

В дополнение к языку, Lua поставляется с набором runtime-библиотек. Эти библиотеки также написаны на ANSI C и напрямую слинкованы с интерпретатором Lua. Как результат, нет нужны устанавливать переменные окружения PATH или предоставлять вспомогательные файлы при разработки приложения с интегрированным Lua.


Расширяя Lua.

Lua — мощный язык, предоставляющий решение проблем в некоторых областях. Python, Ruby и Perl ещё столь же полезны в этом. Главное превосходство Lua над остальными языками это его компактный, эффективный размер. Этот размер, а также простота интеграции и расширения, превращает Lua в практичный язык, достойный изучения.

Lua легко встраивается в сборку проекта за счет ANSI C кода, который требует немногого для конфигурации и не зависит от внешних библиотек (сверх рантайм библиотеки C). Так что можно добавить код интерпретатора Lua прямо при сборке проекта. Обзор мэйкфайлов показывает все полезные настройки для конфигурации. Настроить Lua для буквально любой платформы, которая поддерживает разработку на ANSI C, очень просто.

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

Представьте программу, долго обрабатывающую данные. Пользователю нужна возможность установить максимальное время выполнения этой обработки до того, как она будет отменена. Назовем это значение maxtime. Следующую функция, названную loadconfig, программа может вызвать для загрузки пользовательского файла настроек:
#include 
#include 

void loadconfig(char *file, int *maxtime)
{
    /* Запускаем библиотеку Lua */
    lua_State *L = lua_open();

    /* Откроем математическую библиотеку
     * для вычислений */
    lua_pushcfunction(L,luaopen_math);
    lua_pushstring(L,LUA_MATHLIBNAME);
    lua_call(L,1,0);

    /* Загружаем и обрабатываем файл, 
     * используем lua_pcall чтобы его интерпретировать */
    if (luaL_loadfile(L,file) || lua_pcall(L,0,0,0))
      /* my_lua_error просто выводит ошибку 
       *  и прекращает выполнение */
      my_lua_error(L,"cannot load file: %s",lua_tostring(L,-1));

    /* Загружаем глобальную переменную 
     *  maxtime в стек */
    lua_getglobal(L,"maxtime");

    /* Проверяем, является ли она числом. -1 указывает
     *  на первую позицию стека из его верхушки. */
    if (!lua_isnumber(L,-1))
       my_lua_error(L,"maxtime should be a number\n");

    /* Получаем значение из стека и запоминаем его */
    *maxtime = (int)lua_tonumber(L,-1);

    /* Вот и все */
    lua_close(L);
}

Пользователь может использовать os.getenv для связки с переменной окружения HOSTNAME и установки значения maxtime в зависимости от используемого компьютера. В конечном счете, бывает полезным предоставлять пользователю больше, чем глобальные переменные для управления. Расширяя Lua до уровня доступного API, привязанного к программе, можно предоставить пользователю большую гибкость. Стоит также отметить, что рантайм библиотека Lya содержит хороший набор примеров кода для изучения.

Каждая функция расширения в Lua, написанная на C имеет одну и ту же сигнатуру. Она принимает контекстный объект Lua, традиционно называемый L и затем возвращает целое число, обозначающее количество возвращаемых значений. (Функции Lua могут возвращать больше одного значения). Вы можете получать параметры и возвращать значения через простой, основанный на стеке API, управляющий контекстным объектом. API дает возможность класть в стек и доставать из него любой тип данных Lua. Также есть набор API-функций для управления таблицами (передается по ссылке) и строками.

Для демонстрации расширяемости Lua, ниже приведен пример, делающий функцию gethostbyaddr, которая возвращает информацию о имени хоста TCP/IP по данному IP-адресу, доступной в Lua. В C функция gethostbyaddr возвращает структуру hostent. Элементы этой структуры включают в себя имя хоста, тип адреса, размер адреса, любые алиасы, связанные с именем хоста и массив алиасов хоста. Вместо этого, она может возвращать одну таблицу, дублирующую структуру hostent, делая это проще и чище.

Код берет адрес хоста из стека (первый параметр). Затем он вызывает версию из C функции gethostbyaddr. Наконец, он берет все поля структуры и кладет их в стек, как возвращаемые значения.
/* Возвращает имя хоста и таблицу
 * алиасов по заданному IP-адресу */
static int l_gethostnames(lua_State *L)
{
  /* Получает аргумент и проверяет, что он – строка */
  const char *addr = luaL_checkstring(L,1);

  /* Конвертирует аргумент в тип addr 
   * для передачи в gethostbyaddr */
  unsigned long iaddr = inet_addr(addr);

  /* Будем возвращать таблицу, начинающуюся
   * на t[1] в стиле Lua */
  int tableIndex = 1;
  
  /* Делаем вызов gethostbyaddr */
  struct hostent *h = 
    gethostbyaddr((char *)&iaddr,sizeof(iaddr),AF_INET);

  if (!h) {
    /* Если gethostbyaddr возвращает ошибку,
     * будем возвращать два nil */
    lua_pushnil(L);
    lua_pushnil(L);
  } else {
    /* gethostbyaddr вернул значение.  
     * кладем прямое имя */
    lua_pushstring(L,h->h_name);
    
    /* Создаем таблицу.  До этого мы положили
     * строку и пустую таблицу в стек.  */
    lua_newtable(L);

    /* Если есть алиасы, получаем их и
     * кладем в таблицу, созданную в стеке */
    while (h->h_aliases[tableIndex - 1]) {
      /* Сначала кладем ключ и значение
       * данной записи таблицы в стек
       */
      lua_pushnumber(L,tableIndex);
      lua_pushstring(L,h->h_aliases[tableIndex - 1]);

      /* lua_settable берет два последних элемента стека 
       * и разбивает из на пары ключ/значение.  Эта пара 
       * добавляется в индекс таблице.  Отрицательные
       * индексы возвращаются из верхушки стека
       * В этом случае ключ на -2, значение на -1, а
       * создаваемая  с помощью lua_newtable таблица, на -3
       */
      lua_settable(L,-3);
      tableIndex++;
    }
  }

  /* В любом случае для возврата 
   * мы оставляем два элемента в стеке. */
  return 2;
}

Добавьте вызовы в lua_pushcfunction(L,l_gethostnames); lua_setglobal(L,"gethostnames"); в некоторых местах после инициализации интерпретатора Lua чтобы сделать функцию gethostnames доступной из Lua.


Заключение.

Теперь вы имеете представление о том, каков язык Lua. Так же вы увидели, как просто вы можете интегрировать его в свое приложение. Если вы заинтересованы в использовании Lua, вы можете посетить следующие ресурсы. Первый и самый важный, потратьте немного времени, прочитав книгу Roberto Ierusalimschy Программирование на Lua, которая доступна как в печатном виде, так и в свободном доступе онлайн. Следующий прекрасный ресурс — это Lua Reference Manual, показывающий насколько эффективным может быть этот язык. Сообщество программистов lua предоставляет прекрасные ресурсы, включая вики и почтовые рассылки. Наконец, LuaForge – онлайн репозиторий программ и библиотек, написанных на Lua.


Keith Fieldhouse,
перевод Виктора Черкасова.






Теги: lua, programming

Статьи с такими же тегами:

Изучаем параметры gcc.

Язык
English/Английский
Поиск
Расширенный Поиск
Ошиблись?
Если вы обнаружили ошибку на сайте, пожалуйста, сообщите нам о ней.
Посчитали
0 / 1133
К нам сегодня зашли 5 роботов. Они хотят убить всех человеков.

Зарегистрированных пользователей: 0
Онлайн: 0

Время генерации: 0.010 с
NetSago.v2.β © [2006;∞)  Neunica