-- с двойного тире начинается однострочный комментарий --[[ А если добавить двойные квадратные скобки получится многострочный комментарий --]] ---------------------------------------------------- -- 1. Переменные и управляющие конструкции ---------------------------------------------------- num = 42 -- Все числа в Lua представляют из себя числа с плавающей точкой двойной точности (double) -- Не переживайте, у 64-битных double имеется 52 бита -- для хранения точных целочисленных (int) значений; -- для целочисленных значений, которым нужно менее 52 бит, никаких проблем не возникнет s = 'walternate' --строки неизменны (нельзя переназначать) как в Рython'e t = "double-quotes are also fine" -- можно использовать и двойные кавычки u = [[ Double brackets start and end multi-line strings.]] -- Двойные квадратные скобки -- обрамляют многострочные строки (strings) t = nil -- обнуляет t; В Lua имеется "сборщик мусора"
-- Блоки обозначаются ключевыми словами такими как do/end: while num < 50 do num = num + 1 -- в Lua нет операторов ++ или -- или += end -- Блоки условия if num > 40 then print('over 40') elseif s ~= 'walternate' then -- ~= обозначает неравенство -- равенство проверяется оператором == как в Python; -- используется и для строк io.write('not over 40\n') -- Стандартный вывод else -- Переменные "глобальны" изначально thisIsGlobal = 5 -- без комментариев -- Как создать локальную переменную local line = io.read() -- Считывает следующую строку -- Для соединения строк используется оператор .. (две точки) print('Winter is coming, ' .. line) end -- Обнулённые переменные возвращают nil. -- Это не будет ошибкой: foo = anUnknownVariable -- Теперь foo = nil. aBoolValue = false -- Только типы nil и false возвращают "false"; -- 0 и '' (пустая строка) возвращают "true"! if not aBoolValue then print('twas false') end -- Следующее выражение подобно конструкции a?b:c в C/js: ans = aBoolValue and 'yes' or 'no' --> 'no' karlSum = 0 for i = 1, 100 do -- Диапазон включает оба конца (1 и 100) karlSum = karlSum + i end -- Используйте "100, 1, -1", чтобы считать с конца fredSum = 0 for j = 100, 1, -1 do fredSum = fredSum + j end -- В целом схема такова: for "начальное значение", "конечное значение","шаг" -- Цикл с постусловием: repeat print('the way of the future') num = num - 1 until num == 0 ---------------------------------------------------- -- 2. Функции ---------------------------------------------------- function fib(n) if n < 2 then return 1 end return fib(n - 2) + fib(n - 1) end -- закрытые и безымянные функции тоже допустимы function adder(x) -- Возвращаемая функция создаётся когда вызывается adder -- и запоминает значение x: return function (y) return x + y end end a1 = adder(9) a2 = adder(36) print(a1(16)) --> 25 print(a2(64)) --> 100 -- Функции можно возвращать, вызывать и передавать -- со списками, которые могут не совпадать по длине -- Несовпадающие полученные параметры обнуляются -- Несовпадающие переданные - отбрасываются x, y, z = 1, 2, 3, 4 -- Сейчас x = 1, y = 2, z = 3, а 4 отброшено function bar(a, b, c) print(a, b, c) return 4, 8, 15, 16, 23, 42 end x, y = bar('zaphod') --> напечатает "zaphod nil nil" -- Теперь x = 4, y = 8, а значения 15..42 отброшены -- Функции могут быть локальными и глобальными -- Следующие выражения равнозначны: function f(x) return x * x end f = function (x) return x * x end -- Также как и: local function g(x) return math.sin(x) end local g; g = function (x) return math.sin(x) end -- Кстати, тригонометрические функции работают с радианами -- Вызывать однострочные параметры можно и без скобок print 'hello' -- Работает! ---------------------------------------------------- -- 3. Таблицы ---------------------------------------------------- -- Таблицы = составные данные структуры в Lua; -- они являются ассоциативными массивами. -- Подобно массивам в php или объектам в js , -- ищут по хеш-значениям и могут быть использованы как списки -- хранение данных в таблице по типу "значение-ключ": -- Переменные имеют строковые ключи по умолчанию t = {key1 = 'value1', key2 = false} -- Строковые ключи могут обозначаться с точкой как в js: print(t.key1) -- Напечатает 'value1'. t.newKey = {} -- Добавляет новую пару "значение-ключ" t.key2 = nil --Удаляет key2 из таблицы -- объявление таблицы с указанием ключей и значений (кроме nil): u = {['@!#'] = 'qbert', [{}] = 1729, [6.28] = 'tau'} print(u[6.28]) -- напечатает "tau" -- Сопоставление ключей идёт, в основном, по значениям строк и чисел -- но позволительно использовать и таблицы. a = u['@!#'] -- Теперь a = 'qbert'. b = u[{}] -- Мы ожидаем, что это будет 1729, но на самом деле это nil: -- b = nil т.к. найти значение не удалось, из-за того, что -- ключ, который мы использовали не является тем же объектом, -- что мы использовали для сохранения значения. -- Отсюда вывод: лучше использовать в качестве ключей строки и числа. -- Вызывать таблицу с одним параметром можно и без скобок: function h(x) print(x.key1) end h{key1 = 'Sonmi~451'} -- Напечатает 'Sonmi~451'. for key, val in pairs(u) do -- Перебор таблицы print(key, val) end -- _G это особая таблица для всех глобальных переменных print(_G['_G'] == _G) -- Выдаст 'true'. -- Использование таблиц как списков/массивов: -- Значениям списка неявно присваивается числовой ключ: v = {'value1', 'value2', 1.21, 'gigawatts'} for i = 1, #v do -- #v размер списка v print(v[i]) -- Индексирование начитается с 1 !! Безумие! end -- Вообще-то нет такого типа как список. v это просто таблица -- с последовательными числовыми ключами. ---------------------------------------------------- -- 3.1 Метатаблицы и метаметоды ---------------------------------------------------- -- Таблицы могут иметь метатаблицы, что позволяют -- "перегружать" их. Позже мы рассмотрим, -- как с помощью метатаблиц реализовать js-прототипное поведение. f1 = {a = 1, b = 2} -- Представляет деление a/b. f2 = {a = 2, b = 3} -- Вот так не получиться: -- s = f1 + f2 metafraction = {} function metafraction.__add(f1, f2) sum = {} sum.b = f1.b * f2.b sum.a = f1.a * f2.b + f2.a * f1.b return sum end setmetatable(f1, metafraction) setmetatable(f2, metafraction) s = f1 + f2 -- вызывает __add(f1, f2) в метатаблице f1 -- f1, f2 не имеют ключей в метатаблицах, в отличии от -- прототипов в js, они находятся по функции -- getmetatable(f1). Метатаблица - та же таблица с -- специальными для Lua ключами, например __add. -- Выполнить следующую строку не удастся, -- так как s не имеет своей метатаблицы: -- t = s + s -- Создание подобия классов поможет это исправить: defaultFavs = {animal = 'gru', food = 'donuts'} myFavs = {food = 'pizza'} setmetatable(myFavs, {__index = defaultFavs}) eatenBy = myFavs.animal -- Работает! Спасибо метатаблице! -- Если во время поиска не нашлось значение в таблице, -- совершается повторный поиск в поле __index метатаблицы -- Значением __index может быть и функция function(tbl, key) -- __index,add, .. называются метаметодами -- Полный список смотрите ниже: -- __add(a, b) for a + b -- __sub(a, b) for a - b -- __mul(a, b) for a * b -- __div(a, b) for a / b -- __mod(a, b) for a % b -- __pow(a, b) for a ^ b -- __unm(a) for -a -- __concat(a, b) for a .. b -- __len(a) for #a -- __eq(a, b) for a == b -- __lt(a, b) for a < b -- __le(a, b) for a <= b -- __index(a, b) [fn or a table] for a.b -- __newindex(a, b, c) for a.b = c -- __call(a, ...) for a(...) ---------------------------------------------------- -- 3.2 Подобие классов и наследование ---------------------------------------------------- -- В Луа нет классов как таковых. -- Но существуют разные способы их "создания" -- Смотрети пример ниже: Dog = {} -- 1. function Dog:new() -- 2. newObj = {sound = 'woof'} -- 3. self.__index = self -- 4. return setmetatable(newObj, self) -- 5. end function Dog:makeSound() -- 6. print('I say ' .. self.sound) end mrDog = Dog:new() -- 7. mrDog:makeSound() -- 'I say woof' -- 8. -- 1. Dog действует как класс; хотя на самом деле это таблица -- 2. Запись функции function tablename:fn(...) равна -- function tablename.fn(self, ...) -- : (двоеточие) просто добавляет первым аргументом self -- Ещё раз прочтите строки 7, 8, чтобы посмотреть как это работает -- 3. newObj экземпляр класса Dog. -- 4. self = экземпляр класса. Довольно часто -- self = Dog, но наследование может это изменить -- newObj получает функции self когда мы назначаем -- метатаблицу newObj self'у -- 5. Напоминаем: setmetatable возвращает первый аргумент -- 6. : (двоеточие) работает также как и во 2 строке, -- но на этот раз self - экземпляр, а не класс -- 7. Также как Dog.new(Dog), отсюда self = Dog в new(). -- 8. Также как mrDog.makeSound(mrDog); self = mrDog. ---------------------------------------------------- -- Пример наследования: LoudDog = Dog:new() -- 1. function LoudDog:makeSound() s = self.sound .. ' ' -- 2. print(s .. s .. s) end seymour = LoudDog:new() -- 3. seymour:makeSound() -- 'woof woof woof' -- 4. -- 1. LoudDog получает методы и переменные Dog -- 2. self получает поле 'sound' из new(), смотри строку 3. -- 3. Создаётся экземпляр LoudDog. -- 4. Поле 'makeSound' находится LoudDog; -- Тоже что и LoudDog.makeSound(seymour). function LoudDog:new() newObj = {} -- назначаем newObj self.__index = self return setmetatable(newObj, self) end ---------------------------------------------------- -- 4. Модули ---------------------------------------------------- --[[ Я просто закомметил эту часть статьи -- но код в ней всё так же рабочий. -- Предположим, файл mod.lua выглядит так: local M = {} local function sayMyName() print('Hrunkner') end function M.sayHello() print('Why hello there') sayMyName() end return M -- Другой файл может использовать функционал mod.lua local mod = require('mod') -- Запускает mod.lua. -- require стандартный метод подключения модулей -- require работает так: (if not cached; see below) local mod = (function () [contents of mod.lua] end)() -- Получается как mod.lua это тело функции, поэтому -- локальные переменные в mod.lua доступны и за его пределами -- Здесь переменная mod = M в файле mod.lua: mod.sayHello() -- Поздоровались с Hrunkner. -- А вот это неверно; sayMyName существует только в mod.lua: mod.sayMyName() -- ошибка -- Значения, возвращаемые require, кешированы -- и запускаются только раз, даже если вы написали require несколько раз -- Предположим, mod2.lua содержит "print('Hi!')". local a = require('mod2') -- Напечатает Hi! local b = require('mod2') -- Не напечатает; a=b. -- dofile подобен require но без кеширования: dofile('mod2') --> Hi! dofile('mod2') --> Hi! (может вызываться много раз, в отличии от require) -- loadfile загружает файлы .lua но не запускает их f = loadfile('mod2') -- Вызвав f(), запуститься mod2.lua. -- loadstring функция подобна loadfile только для строк g = loadstring('print(343)') -- Возвращает функцию g() -- выводит 343; --]] ---------------------------------------------------- -- 5. Ссылки ---------------------------------------------------- --[[ Я начал учить Lua, потому что хотел делать игры на Love 2D game engine. Вот так вот. Начинал я со статьи "BlackBulletIV's Lua for programmers" После прочитал официальную книгу "Programming in Lua" Вот так и учил. Так же может быть полезным прочитать коротенькую справку на lua-users.org. В этой статье не освещена работа с основными библиотеками * string library * table library * math library * io library * os library Кстати, статья представляет из себя рабочий .lua скрипт. Можете сохранить и запустить. Статья изначально писалась для сайта tylerneylon.com. (ссылка на оригинал статьи: http://tylerneylon.com/a/learn-lua/) Вольный перевод на русский выполнен для сайта xgm.ru Наслаждайтесь Lua!Пару ссылок по Lua:
Простая но удобная IDE с отладчиком и доп. библиотеками - https://code.google.com/p/luaforwindows/
Краткая дока по языку - https://sites.google.com/site/ltwood/projects/lua/lua-lang
Мануал - http://www.lua.org/manual/5.1/manual.html
Комментариев нет:
Отправить комментарий