Love2D: Lua за 15 минут

» Раздел: Lua

LUA ЗА 15 МИНУТ!
ну почти...
Краткий обзор синтаксиса Lua 5.2
Для новичков довольно сложна в понимании,
а вот люди, которые уже знакомы с программированием на других языках,
разберутся без особых проблем.
-- с двойного тире начинается однострочный комментарий

--[[
     А если добавить двойные квадратные скобки
	 получится многострочный комментарий
--]]
----------------------------------------------------
-- 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 "начальное значение", "конечное значение","шаг"
--                                               end
-- Цикл с постусловием:
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!
Спасибо пользователю prog за помощь

Просмотров: 8 280

» Лучшие комментарии


Андреич #1 - 4 года назад 1
ну вот и первая статейка ^_^
если нашли какие-нибудь ошибки, неточности перевода, неправильное толкование - пишите...
girvel #2 - 4 года назад -2
Андреич, итак.
  1. Начал с комментариев
  2. Переменные
  3. Блоки
  4. Лень читать
Реакция человека, не знающего программирования: ничего не понял.
Моя реакция: [мат]
Андреич #3 - 4 года назад 1
мда... зря я это написал в краткое описание, которое ещё фиг найдёшь...
"Статья рассматривает только основной синтаксис, и не подходит для людей, которые вообще не имеют представления о программировании"
Чуть позже, будут и для новичков статьи...
prog #4 - 4 года назад 3
Андреич, можешь полностью игнорировать гирвела - его достаточно полно описывает вот это
girvel:
Лень читать
и вот это
girvel:
Моя реакция: [мат]
что касается самой статьи - комментарии местами кривоваты и вводят в заблуждение
Также стоит уточнить для какой это версии Lua - в последних версиях произошло довольно много изменений, в то время как во многих местах используется более ранняя версия.
I_D_ #5 - 4 года назад 0
более менее понятно хотя статья походит больше на справку для уже немного знающих LUA
Это сообщение удалено