Skip to content

Lua для чайников

Не решенные Туториалы
  • Все вы, наверное, знаете его:

    lua

    Ой, не то…

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

    гайд перенесен с прошлого форума, я обьединил все три его части в одну

    Универсальный гайд по входу в кодинг на Lua

    гайд полностью написан мной (t1m1yep) при помощи своих знаний и документации Lua для octothorp team и его сообщества 🙂

    Установка IDE и Lua

    давай начнем с установк всего необходимого для разработки:
    для начала установим среду разработки - IDE (англ. интегрированная среда разработки)
    она понадобится нам чтобы писать наш код

    предлагаю тебе использовать visual studio code, но если ты знаком с любым другим IDE, можешь пользоваться им
    установить vs code
    после установки открывай visual studio code (дальше для удобства буду его называть VSC)
    в левой части интерфейса будет кнопка с квадратиками, в ней мы выберем необходимые дополнения (скриншот ниже, нажимай туда)

    в строку поиска пиши Lua и нажимай установить на расширении, показанном на скриншоте

    Описание

    делай тоже самое с расширением glua (тоже показано на скриншоте)

    Описание

    теперь установим Lua. смотреть гайд тут (НЕ МОЙ):

    видео гайд
    нужный сайт для установки

    теперь ты готов к разработке!

    учимся писать код!

    откроем папку для разработки, рекомендую создать отдельную папку (смотреть скриншот)

    Описание

    теперь создадим файл: (смотреть скриншот)

    img

    нажимаем на кнопку создать файл и вводим:

    main.lua
    

    в этом случае main - название файла, а .lua это расширение файла. название файла вы можете сделать своим, но расширение обязательно .lua

    после этого откроется окошко с вводом кода, туда мы будем писать код
    Описание

    также в VSC удобный встроенный терминал. для этого нажмите словосочетание

    CTRL + ` (апостроф)
    

    переведи курсор в верхнюю панель с кодом и готовься запоминать

    терминология

    переменная - ячейка с определенным названием и значением:

    название_переменной = значение_переменной
    

    переменные могут быть глобальными и локальными. локальные имеют перед названием слово “local”:

    local название_переменной = значение_переменной
    

    типы данных в Lua

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

    string - строка

    моя_крутая_строка = "привет, мир!"
    

    строка ВСЕГДА обьявляется в кавычках!! это очень важно, если их не указать, компьютер будет искать переменную вместо строки, так как именно переменные указываются без кавычек!!!

    number - число

    мое_крутое_число = 5
    

    также число может быть дробью:

    моя_крутая_дробь_тоже_число = 5.5
    

    boolean - булево значение

    вы наверняка знаете “true” и “false” из учебников английского языка 5 класса 🙂

    мое_крутое_булево_значение = true
    

    и еще:

    мое_крутое_булево_значение = false
    

    если не знаете английский, true - правда, false - ложь

    nil - ничего

    nil - буквально ничего 🙂

    мое_крутое_ничего = nil
    

    function - функция

    function моя_крутая_функция(мой_крутой_аргумент_функции)
    

    пока что ты еще не знаешь о функциях, но мы поговорим о них прямо в следующем параграфе!

    в этом параграфе я рассказал тебе только о самых базовых типах, всего их восемь, об остальных мы поговорим позже

    функции

    функция имеет аргумент (иногда его не может быть) и название, также она может возвращать значение. давай посмотрим на примере:

    function название_функции(аргумент_функции) -- обьявляем функцию
          local переменная = 10 -- обьявляем переменную
          return переменная -- возвращаем переменную
    end -- обьясняем компьютеру, что наша функция закончилась
    

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

    **также функция может принимать аргументы: **

    function суммировать(а, б) -- создаем функцию
        local сумма = а + б -- создаем переменную, равную сумме аргументов а и б
        return сумма -- возвращаем нашу переменную сумма
    end -- заканчиваем функцию
    

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

    теперь вызовем функцию:

    суммировать(10, 50)
    

    функция должна быть обьявлена выше, чем ее вызов в коде!

    чтобы вывести результат функции, нам понадобится вызов встроенной функции print:

    print(суммировать(10, 50))
    

    также можем вывести любую другую переменную через функцию print:

    print("привет, челог!")
    

    для этого понадобится отправить строку в кавычках, как я говорил раньше в параграфе с типами данных!! если этого не сделать, компьютер будет искать переменную вместо строки

    также можно вывести переменную:

    local строка = "привет, челог!"
    print(строка)
    

    разницы между двумя верхними примерами нет

    условия

    условия позволяют выполнять определенный отрывок кода только если условие соблюдается

    условия if и else

    local a = 10 -- обьявляем переменную a
    local b = 5 -- обьявляем переменную b
    if a > b then -- говорим компьютеру: ЕСЛИ а БОЛЬШЕ б, ТОГДА печатай текст
         print("переменная а больше чем б!")
    end
    

    условие также имеет табуляции и заканчиваются с помощью end. в этом случае нам напишет строку “переменная а больше чем б!”

    но если мы поменяем переменные значениями (тоесть переменная a станет равна 5, а переменная b станет 10)

    теперь введем еще одно условие else

    local a = 10
    local b = 5 
    if a > b then 
         print("переменная а больше чем б!")
    else -- говорим компьютеру, что если условие не выполняется, то печатаем текст
        print("функция не подошла не под одно условие!!")
    end
    

    elseif

    а что если может быть еще один вариант? если переменные равны, и нам надо напечатать текст именно о том, что переменные равны? в таком случае нам поможет условие elseif

    local a = 10
    local b = 5 
    if a > b then 
         print("переменная а больше чем б!")
    else if a == b -- иначе если а == б
         print("переменная а равна б!") -- печатаем текст
    else
        print("функция не подошла не под одно условие!!")
    end
    

    вот так выглядят условия. и да, end у них один, так как они считаются одним блоком кода

    когда мы сравниваем две переменные на равенство, пишется два знака “=”, а если присваеваем переменной значение, пишется один знак “=”

    ввод и вывод

    есть три потока - stdIN, stdOUT, stdERR
    нас интересуют только первые два (пока что)
    stdin - осуществляет пользовательский ввод из консоли
    stdout - осуществляет вывод данных в консоль
    чтобы пользователь мог ввести значение переменной, рассмотрим такой код:

    local переменная = io.read()
    

    мы вызываем функцию read из библиотеки io (input/output)

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

    local переменная = io.read()
    print(переменная)
    

    массивы

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

    local массив = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
    

    так создается массив, в массиве количество элементов считается от нуля, тоесть последним индексом этого массива будет 9, а первым 0
    обратимся к 5 индексу массива в этом коде (это число 6):

    local массив = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
    print(массив[5]) -- в квадратных скобках после названия переменной указываем индекс переменной в массиве
    

    циклы

    циклы позволяют нам выполнять один блок кода н-нное количество раз. один такой раз называется одной ИТЕРАЦИЕЙ

    операторы (важно)

    = - оператор присваивания
    == - оператор сравнения (если переменные равны)
    ~= - оператор сравнения (если переменные не равны)
    < - оператор меньше
    > - оператор больше
    <= - оператор меньше-равно
    >= - оператор больше-равно

    while

    while переводится как “пока”, тоесть компьютер делает какой то блок кода пока условие выполняется. грубо говоря, if вместе с циклом.

    рассмотрим цикл while:

    local i = 0 -- i это общепринятое название переменной обозначающей количество итераций
    local limit = 10 -- количество итераций
    while i < limit do -- пока i меньше переменной limit (10) делай этот блок кода
         print(i) -- печатаем переменную i
         i = i + 1 -- i равняется i плюс 1
    end
    

    этот код выведет числа от 0 до 9

    repeat (repeat-until)

    repeat -- повторять
            line = io.read() -- считываем ввод от пользователя
        until line ~= "" -- если ввод пользователя не пустая строка, то повторяем еще раз
        print(line) -- печатаем последний ввод пользователя
    

    repeat перевыполняет код еще раз, если условие until выполняется. until выполняет роль if

    числовой for

    цикл for - переводится как “пока”, как и while, только используется в других целях и имеет другой вид

    for i = 1, 10 do
        print(index)
    end
    

    for делает “шаги”, после каждого автоматически прибавляя 1 к переменной i, а число 10 после запятой здесь означает количество шагов. этот код выведет числа от 1 до 10

    рядовой for

    сразу попрошу учесть что рядовой for не военный и даже не служит в армии! рядовой тут означает - по рядам

    рядовой for позволяет итерироваться (перевыполнятся) блоку кода пока в данном ему массиве имеются элементы.
    рассмотрим этот код:

    local a = {10, 20, 30, 40, 50, 60, 70, 80, 90, 100}
    for i,v in ipairs(a) do -- i (индекс обьекта в массиве) и v (значение массива с индексом i) в ipairs(массив)
        print(v) -- печатаем значение массива с индексом i
    end
    

    ipairs() - функция которая возвращает сразу два значения: индекс значения в массиве и само значение в массиве. перестает возвращать значения когда массив заканчивается, следственно, цикл тоже останавливается

    возвращать два значения легко - return первое_значение, второе_значение . просто перечисли через запятую!

    break

    break позволяет остановить цикл вне его выполнения
    рассмотрим данный код:

    local a = {10, 20, 30, 40, 50, 60, 70, 80, 90, 100}
    for i,v in ipairs(a) do -- i (индекс обьекта в массиве) и v (значение массива с индексом i) в ipairs(массив)
        if v == 50 then break end -- если значение массива равняется 50, останавливаем цикл
        print(v) -- печатаем значение массива с индексом i
    end
    

    да, условия в одну строку реализуются только если блок, выполняемый в условии однострочный: if 10 > 20 then print(“10 меньше 20!!”) end

    В этой главе:

    • таблицы
    • строки (продвинуто)
    • замыкания
    • конструкторы
    • функции (продвинуто)
    • библиотеки и require
    • работа с ошибками (error handling)
    • корутины
    • условия (продвинуто)
    • и закрепим предыдущий материал!

    таблицы

    таблица представляет из себя “массив”, который вместо индекса имеет ключ. рассмотрим на примере:

    local mytable = {} -- инициализируем пустую таблицу
    local key = "taiwan" -- создаем переменную-строку "ключ"
    mytable[key] = "roobys" - задаем значение обьекту таблицы с ключом который мы создали ранее
    print(mytable[key]) -- выводим значение обьекта таблицы  с ключом key!
    

    этот код выведет строку “roobys”. давайте немного изменим этот код, в частности, последнюю строку:

    local mytable = {} -- инициализируем пустую таблицу
    local key = "taiwan" -- создаем переменную-строку "ключ"
    mytable[key] = "roobys" - задаем значение обьекту таблицы с ключом который мы создали ранее
    print(mytable) -- выводим таблицу без ключа! саму переменную
    

    выведется что то по типу “table: 0x158e09d80”
    что это?!
    это адрес таблицы в памяти компьютера. ее местоположение, ячейка, которую она занимает в ОЗУ

    мы можем инициализировать таблицу по другому:

    local mytable = {["skumbri"]="скумбри", ["р12"]="r12", ["zverok99"]="зверек99"}
    

    в этом случае мы заранее инициализировали обьекты нашей таблицы и ключи к ним. mytable с ключом “skumbri” хранит значение “скумбри”!

    также мы можем создать таблицу-матрешку:

    local octothorp_team = {
        managers = {["inquizzy"]="инквиззи", ["vondik"]="вондик"}, 
        admins = {["skumbri"]="скумбри", ["campot"]="кампот"} 
    }
    print(octothorp_team.managers["inquizzy"])
    print(octothorp_team.admins["campot"])
    

    только в этом случае нам надо будет обращаться к под-таблицам через точку “.”

    примечание: ключи могут быть как и строками, так и числами и даже boolean’ами
    примечание: ключи в таблицах указываются в квадратных скобках, а после, через равно идет значение

    пример итерации по обьектам таблицы:

    local octothorp_team = {["doctor"]="доктор",["kilo7"]="кило-семь", ["polkin"]="полкин"}
    for key, value in pairs(octothorp_team) do 
        print(key, value)
    end
    

    в этом случае я использовал функцию pairs()
    этот код выведет:

    polkin  полкин
    kilo7   кило-семь
    doctor  доктор
    

    замыкания

    замыкания - “мини функции”
    рассмотрим на примере:

    local myfunction = function (a, b)
        return a + b
    end
    
    print(myfunction(10, 10))
    

    для удобства и чистоты кода - сделаем обьявление функции-замыкания однострочным

    local myfunction = function (a, b) return a + b end
    
    print(myfunction(10, 10))
    

    получается, что мы задаем нашей переменной myfunction значение функции. уже забыл?! функция - это тоже тип данных! я говорил об этом в первой части.

    мы можем вызывать эту переменную точно также как и функцию. рассмотрим еще один пример:

    function create_closure() 
        return function(a, b) return a + b end
    end
    
    local closure_function = create_closure()
    
    print(closure_function(1, 2))
    

    closure - замыкание по английски.
    мы создаем функцию, которая возвращает функцию-замыкание, а эта функция-замыкания суммирует два числа. получается, что функции точно также могут возвращать функции-замыкания с помощью return. прямо как обычные числа и строки!

    строки

    был бы это си… ой, что-то я замечался, продолжим!
    строки имеют свою собственную библиотеку! как бы это банально не звучало, звать ее - string!
    рассмотрим функцию gsub библиотеки string. она может заменить часть строки!

    local a = "доброград плохой сервер" -- создаем строку
    local b = string.gsub(a, "плохой", "крутой")  -- меняем часть строки и записываем в другую переменную
    print(a)       -- неправильная строка
    print(b)       -- правильная строка
    

    **выводом будет: **

    доброград плохой сервер
    доброград крутой сервер
    

    аргументы функции gsub() - первоначальная строка, с которой будут проводится манипуляции; слово которое должно быть изменено; слово НА которое надо изменить
    функция gsub() возвращает обновленную строку

    операции с задним слэшем (форматирование текста)

    задний слэш - “” в составе строки может иметь после себя определенную букву. каждая строка заканчивается на “\0” - nil символ, он обозначает конец строки. ты его даже не замечаешь! но запомни это, ведь любой инструмент может тебе пригодится (даже старая мышь, вдруг новая сломается!)

    \n - знак новой строки. все что будет после него - с новой строки
    \t - табуляция
    \r - очистить всю консоль! (не ставь это в конце, иначе ничего не увидишь 🙂 лучше ставь в начале!)
    также имеется большое количество таких операций, их ты можешь найти в интернете.

    ТВОЙ РОДНОЙ ЯЗЫК ДЖАВАСКРИПТ ЧТО ЛИ С**А?!

    наверняка многие из вас видели этот мем
    Описание
    это происходит из за сложения строк

    local яблоко = "яблоко"
    local одно = "одно"
    local одно_яблоко = одно + яблоко
    

    да, баян, но я считаю что стоит осветить эту тему 🙂
    также мы получим ошибку если попытаемся провести операцию с двумя разными типами:

    local chelog = "Дмитрий Антонов"
    local pi = 3.14
    local pichelog = chelog + pi -- выдаст ошибку, мы не можем сложить Дмитрия Антонова и 3.14
    print(pichelog) 
    

    Описание

    мы можем сложить яблоко с яблоком, но банан с яблоком не можем.

    таинственный кодер

    конструкторы

    ты до этого применял конструкторы, с таблицами и массивами! да-да, те самые фигурные скобки при создании таблиц и массивов - конструкторы. давай посмотрим пример:

    local массив_админов = {"r12", "skumbri", "campot", "timetocoffee", "what"} 
    local таблица_админов = {["рубус"]="roobys", ["эр12"]="r12", ["скумбре"]="skumbri", ["кампот"]="campot", ["кофейня"]="timetocoffee"} 
    print(массив_админов[3]) -- выведет timetocoffee
    print(таблица_админов["эр12"]) -- выведет r12
    

    Библиотеки, require

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

    представим такую ситуацию: ты вывел в отдельный файл одну очень сложную функцию (нет) которая возвращает строку “Дмитрий Антонов” и теперь хочешь использовать эту функцию и библиотеку в основном файле. тут тебе поможет require:

    файл chelog_library.lua

    function dmitry_antonov() 
        return "Дмитрий Антонов"
    end
    

    файл main.lua

    require "chelog_library"
    
    local dima = dmitry_antonov()
    print(dima)
    

    почему ты написал только название файла в require? где расширение .lua??

    если вы импортируете локальный файл, которого нет папке всех библиотек lua, указывайте только название файла, иначе компьютер будет искать его в корне библиотек и он ее просто не найдет!

    также вы можете импортировать из папки:
    Описание
    в таком случае понадобится указать дочернюю папку в main.lua:

    require "libs/chelog_library"
    
    local dima = dmitry_antonov()
    print(dima)
    

    в файле библиотеки ничего менять не нужно.

    но что если main.lua тоже находится в папке?
    Описание
    в таком случае нам надо задать package.path перед require:

    package.path = package.path .. ";../libs/chelog_library.lua"
    require("chelog_library")
    
    local dima = dmitry_antonov()
    print(dima)
    

    Описание
    а если библиотека находится вне папки libs, а просто папкой выше main.lua, мы можем убрать из package.path путь в папку “/libs”:

    package.path = package.path .. ";../chelog_library.lua"
    require("chelog_library")
    
    local dima = dmitry_antonov()
    print(dima)
    

    условия (продвинутые)

    рассмотрим несколько условий:

    булевы значения в if
    local lovechelog = true
    if lovechelog then 
        print("i love chelog") 
    elseif not lovechelog then
        print("deleting system...")
    end
    

    выведется “i love chelog”, а если заменить lovechelog на false, выведется “deleting system…”

    ключевое слово “not” буквально обозначает “не”

    в случае с булевым значениями не обязательно указывать сравнение по типу: “if boolean == true …”, можно просто написать “if boolean …”, это будет означать одно и тоже. а если надо указать “if boolean == false …”, можно написать “if not boolean”, это означает тоже самое.

    elseif входит в состав конструкции if, так как end у них общий. elseif используется только в случае повторения условия с участием одной и той же переменной.

    “||” и “&&”

    || - “или”

    if 10 > 5 || 20 > 21 then -- выполнится только первая часть условия, но само условие выполнится
         print("octothorp team") -- надпись выведется
    end
    
    if 10 < 5 || 20 < 21 then -- выполнится только вторая часть условия, но само условие выполнится
         print("octothorp team") -- надпись выведется
    end
    

    && - “также”

    if 10 > 5 && 20 > 10 then -- условие выполнится
       print("octothorp team") -- надпись выведется
    end
    
    if 10 > 5 && 20 < 10 then -- условие не выполнится, так как вторая часть не выполнена
       print("octothorp team") -- надпись НЕ выведется
    end
    

    работа с ошибками

    каждый разработчик имеет дело с ошибками и удерживает их (нервно пытается)

    error()

    функция error() принимает строку, которую будет печатать в консоль

    error("ошибка!")
    

    выведет:
    Описание

    assert

    давайте напишем простенькую программу, которая будет выдавать ошибку если мы будем пытаться прибавить число к строке:

    local dima = "dima"
    local num1 = 10
    local numdima = assert(type(num1) == "string", "num1 не должно быть числом") -- assert() вернет false и выключит программу
    print(numdima) -- мы никогда не узнаем...
    print(dima, num1) -- мы никогда не узнаем...
    

    Описание
    поменяем переменную num1 на строку:

    local dima = "dima"
    local num1 = "antonov"
    local numdima = assert(type(num1) == "string", "num1 не должно быть числом") -- assert() вернет true
    print(numdima) -- выведет true
    print(dima, num1) -- выведет "dima antonov"
    

    Описание

    корутины

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

    создадим корутину:

    корутина = coroutine.create(function ()
        print("привет!") -- не выведется, так как горутина запускается в другом потоке!
    end)
    print(корутина) -- выведет thread: <адрес потока в котором запускается горутина>
    print(coroutine.status(co)) -- выведет suspended, корутина приостановлена
    coroutine.resume(co) -- выведет тот самый "привет!" в консоль, однако пожертвует своей жизнью (я не шучу)
    print(coroutine.status(co)) -- выведет dead... корутина умерла..
    

    немного исправим код и добавим coroutine.yield():

    корутина = coroutine.create(function () -- создаем корутину
        for i=1,3 do -- создаем цикл, он запустится три раза
            print("корутина с числом", i) -- печатаем номер итерации цикла
            coroutine.yield() -- функция yield() делает статус suspended, тоесть приостановлена
          end
    end)
    coroutine.resume(корутина) -- теперь мы возобновим коротину. три раза. выведет число 1
    print(coroutine.status(корутина)) -- статус suspended, так как после каждой итерации корутина приостанавливает себя и ждет возобновления
    coroutine.resume(корутина) -- выведет число 2
    print(coroutine.status(корутина)) -- suspended!
    coroutine.resume(корутина) -- выведет число 3
    print(coroutine.status(корутина)) -- suspended!
    

    если мы попытаемся возобновить коротину через coroutine.resume() которая уже мертва, мы получим ошибку

    мы также можем приостанавливать и возобновлять корутину с аргументами:

    корутина = coroutine.create(function (a,b) -- коротина-замыкание с двумя аргументами
        coroutine.yield(a + b, a - b) -- приостанавливаем корутину с аргументами для возобновления
      end)
    print(coroutine.resume(корутина, 20, 10)) -- даем те самые аргументы из yield(). выведет 30
    

    также коротина может возвращать значения как обычная функция:

    корутина = coroutine.create(function ()
        return 6, 7 -- возвращаем числа 6 и 7
      end)
    print(coroutine.resume(корутина))  -- выведет "6 7"
    

    обратная связь (вопросы насчет кода)

    дискорд: t1m1yep

    Универсальный гайд по входу в кодинг на Lua

    В третьей главе:

    • деревья
    • списки (даже научимся создавать их с нуля)
    • библиотека table для работы с таблицами
    • сериализация
    • load()
    • переменная-placeholder
    • навыки гуглить

    библиотека table

    мы уже рассмотрели таблицы, а теперь перейдем к библиотеке для работы с ними. require прописывать не надо, так как библиотека стандартная

    table.insert() и table.remove
    local tbl = {["saber"]="сабер"} -- создаем таблицу
    
    table.insert(tbl, "карасик") 
    -- вставляем в таблицу строку "карасик" без ключа
    -- через table.insert() значение с ключом не вставить!
    
    print(tbl[1]) -- к значению "карасик" придется обратиться, 
    -- по его индексу, как у массива
    
    print(tbl["saber"]) -- а к значению "сабер" которому мы дали ключик, 
    -- обращаться только по ключу!
    
    print(tbl.saber) -- выпечатает сабера, 
    -- так тоже можно обращаться по ключу (через точку)
    
    print(tbl[0]) 
    -- напишет nil, так как к первому ( с нулевым индексом)
    -- которому мы задали ключ, обращаться можно только по ключу
    
    table.remove(tbl, 1)
     -- в table.remove() указать таблицу и индекс, 
    -- обьекта который мы хотим удалить
    print(tbl[1]) 
    -- выведет nil, карасика больше нет!
    
    table.remove(tbl, 0) -- попробуем удалить обьект с ключом..
    print(tbl["saber"]) 
    -- выведет сабера, 
    -- так как к обьекту с ключом по индексу не обратиться!
    
    table.remove(tbl, ["saber"])
    -- table.remove() выведет ошибку, 
    -- так как функция принимает только числа как второй аргумент!
    print(tbl["saber"]) -- мы никогда не узнаем..
    

    table.insert(таблица, индекс, обьект)
    таблица - table
    индекс - number
    обьект - any буквально любой тип, так как таблица может принимать все типы

    но… я уже указывал только таблицу и обьект?
    да, второй аргумент необязателен, поэтому если третего аргумента (обьекта который мы вставляем) нет, то вместо него становится второй аргумент

    table.remove(таблица, индекс)
    таблица - table
    индекс - number

    значения, которые создавались в паре с ключом, по индексу тронуть нельзя

    односвязный список

    односвязный список - переменная которая помимо своего значения содержит следующий элемент списка
    грубо говоря, это матрешка, которая в себе содержит свой следующий элемент

    local lst = { -- создаем список, это называется КОРНЕМ списка, первый обьект
      value = nil, -- список содержит две переменные - его "значение"
      next = nil -- и следующий элемент списка
    }
    lst.value = 10 -- задаем "значение" первого элемента списка десяти
    
    local new_lst = { -- создаем второй элемент списка
      value = nil, -- изначально переменные списка nil
      next = nil
    }
    new_lst.value = 20 -- задаем значение второго элемента двадцати
    lst.next = new_lst -- а теперь задаем в первом элементе списка, как следующий элемент второй
    
    local newnew_lst = { -- создаем третий элемент списка
      value = nil,
      next = nil 
    }
    newnew_lst.value = 30 -- значение третего элемента списка - 30
    new_lst.next = newnew_lst -- следующий список у второго - третий
    
    print(lst.value) -- первый обьект, 10
    print(lst.next.value) -- второй обьект, 20
    print(lst.next.next.value) -- третий обьект, 30
    

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

    деревья

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

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

    local tree_root = {
        value = 10
        left = nil
        right = nil
    }
    

    value - значение
    left - левая ветка
    right - правая ветка

    local tree_root = { -- создаем первую ветку дерева
      value = 10, -- на первой ветке лежит десятка
      left = nil, -- левой ветки пока что нет
      right = nil -- правой ветки пока что нет
    }
    
    local first_right = { -- создаем первую ПРАВУЮ ветку дерева
      value = 20, -- на первой ПРАВОЙ ветке дерева лежит двадцатка
      left = nil, -- левой ветки ОТ ЭТОЙ ветки пока что нет
      right = nil -- правой ветки ОТ ЭТОЙ ветки пока что нет
    }
    tree_root.right = first_right -- задаем правую ветку самой первой ветки, только что созданной веткой
    
    local first_left = { -- создаем первую ЛЕВУЮ ветку
      value = 30, -- на первой ЛЕВОЙ ветке лежит тридцатка
      left = nil, -- от первой ЛЕВОЙ ветки нет еще одной левой ветки
      right = nil -- от первой ЛЕВОЙ ветки нет еще одной правой ветки
    }
    tree_root.left = first_left -- задаем самой первой ветке левую ветку нашей только что созданной левой веткой
    
    print("первая ветка: ", tree_root.value) 
    -- выведется 10, это значение самой первой ветки
    
    print("первая левая ветка: ", tree_root.left.value) 
    -- выведется 20, это значение первой-левой ветки
    
    print("первая правая ветка: ", tree_root.right.value)
    -- выведется 30, это значение первой-правой ветки
    

    это достаточно сложная тема и мне самому понадобилось время чтобы ее понять

    на 99% собеседований на работу программистом спрашивают про деревья!

    сериализация

    сериализация - процесс преобразования объекта в форму, пригодную для сохранения или передачи

    сериализация - это когда ты сохраняешь свою таблицу в текстовый файл, чтобы отправить ее другу!

    рассмотрим пример сериализации с помощью библиотеки IO (input/output):

    local workers = {"Дмитрий Антонов", "Дезроу Дезроев", "Тимофей Коробка"}
    -- создаем массив строк "работников"
    
    save_file = io.open("workers.txt", "w")
    -- через библиотеку io открываем файл workers.txt
    
    io.output(save_file)
    -- говорим программе "дальше выводи все в save_file"
    
    for i = 1, #workers do -- запускаем цикл по всем элементам массива
      io.write(workers[i], "\n")
      -- через io печатаем каждого работника, после ставим \n (знак новой строки)
    end
    
    io.close(save_file) 
    -- обязательно закрываем файл, иначе компьютер будет ждать новых инструкций с файлом
    

    рассмотрим каждую функцию по порядку:

    io.open(название_файла, режим_файла)
    название_файла - string, просто название файла
    режим файла - string, режим открытия файла:

    r - read, только читать; w - write, переписывает весь файл; a - append (добавить), открывает или создает файл для добавления чего-то к нему; r+ - read и write; w+ - read и write, полностью переписывает файл или создает его; a+ - append и read, открывает уже созданный файл или создает новый.

    io.output(файл)
    файл - файл, который был создан с помощью io.open()
    примечание - по умолчанию io.output() - консоль

    for i = 1, #массив do …
    массив - название массива, “#” перед ним позволяет итерироваться столько раз, сколько элементов в массиве

    io.write(содержимое)
    содержимое - строка
    печатает содержимое в io.output(), по умолчанию это консоль

    io.close(файл)
    файл - файл, который был создан через io.open()
    перестает ожидать инструкций о работе с ранее открытым в io.open(). обязателен если был io.open()!!

    пауза

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

    google

    да, навыки гуглить тебе очень пригодятся и я хотел бы дать небольшую базу как их использовать:
    представим что я хочу найти рецепт торта медовика:
    Описание
    А ГДЕ МЕДОВИК?! ПОЧЕМУ ТУТ ВООБЩЕ НЕТ МЕДОВИКА!
    **можно сделать мой запрос таким: **
    рецепт торт "медовик" - я указал медовик в кавычках, это означает что это слово ОБЯЗАТЕЛЬНО должно быть в предложенном результате
    Описание
    результаты лучше!!

    писать на английском (если ты его знаешь)

    представим что я хочу найти как подключится к базе данных через glua:
    Описание
    на русском - результатов нет!
    попробуем на английском:
    Описание
    на английском - результаты есть!!

    переменная placeholder

    делаешь цикл через pairs, но тебе не нужно одно из значений? так просто забей хуй поставь плейсхолдер!

    local tbl = {"chelog", "dima"} -- делаем массив
    for _,v in pairs(tbl) do -- ставим вместо k плейсхолдер (_)
      print(v)
    end
    

    да-да плейсхолдер - нижнее подчеркивание
    он указывает на то, что тебе не нужно получать эту переменную
    а почему просто ничего не ставить на месте k?
    так как k - первый аргумент, v будет иметь значение, подготовленное для k просто с другим названием!

    функция load()

    универсальная и ОЧЕНЬ мощная функция, превращает ЛЮБУЮ строку которую вы ей дадите в функцию:

    local code = "local s = 'привет, мир!'; return s"
    f = load(code)
    print(f())
    

    для обозначения новой инструкции компьютеру в одну строку ставят “;”

    _G (_global)

    глобальная таблица которая позволяет нам вписывать туда новые значения с ключами:

    _G["chelog"] = "dima"
    print(_G["chelog"])
    

    также можно создать глобальную функцию:

    function _G.print_chelog()
      print("chelog")
    end
    _G.print_chelog()
    

    мы присвоили к переменной (таблице) _G функцию print_chelog() и теперь можем обращаться к ней через точку!

    читать документацию glua
    если ты закончил читать этот гайд, то ты просто монстр, спасибо

    Обратная связь:

    дискорд: t1m1yep

  • Имба, автор красава!

  • @t1m1yep не, ну за такое можно и 2000 фишек выдать

  • @vortu если ты поймешь сам луа, то глуа тебе сложным не будет и все можно будет понять по той же документации где на каждую функцию есть
    моя задача это не вырастить из тебя готового разработчика, я не инкубатор, я лишь могу дать пинок под зад вследствие которого ты уже сам изучишь то, что тебе нужно
    да хоть роблокс изучай, там тот же луа (luau) только с некоторыми дополнениями

  • круто сделано, полезно тому, кому интересно.

    самое главное, всем кодерам совет выпрямить спину, следить за здоровьем и быть подписанными на соответствующие паблики ~~> https://vk.com/straighten_your_back

Похожие темы