fbpx

Каталог статей

Каталог статей для размещения статей информационного характера

Как выучить

Roblox Lua Style Guide¶

Roblox Lua Style Guide¶

Это руководство по стилю призвано объединить как можно больше Lua-кода в Roblox под единым стилем и соглашениями.

Это руководство разработано на основе руководства Google по стилю C++. Несмотря на то, что Lua значительно отличается от этого языка, принципы руководства остаются неизменными.

Руководящие принципы¶

  • Цель руководства по стилю – избежать споров.
    • Нет единственно правильного ответа на вопрос, как оформлять код, но последовательность важна, поэтому мы согласны принять этот единый, несколько произвольный стандарт, чтобы мы могли больше времени тратить на написание кода и меньше спорить о деталях форматирования в обзоре.
    • Вы напишете свой код один раз. Многие люди должны будут его прочитать – и рецензенты, и все остальные, кто будет касаться кода, и вы сами, когда вернетесь к нему через полгода.
    • При прочих равных условиях подумайте о том, как могут выглядеть различия. Намного легче читать отличия, которые не предполагают перемещений между строками. Чистые диффы облегчают рецензирование кода.
    • Волшебный код действительно приятно использовать, пока что-то не пойдет не так. Тогда никто не знает, почему он сломался или как его исправить.
    • Метатаблицы – хороший пример мощной функции, которую следует использовать с осторожностью.

    Структура файлов¶

    Файлы должны состоять из следующих элементов (если они присутствуют) по порядку:

    1. Необязательный блок-комментарий, рассказывающий о том, почему этот файл существует.
      • Не прикрепляйте имя файла, автора или дату – эти вещи может сообщить нам наша система контроля версий.
    2. Сервисы, используемые файлом, с помощью GetService
    3. Импорт модулей, с помощью require
    4. Константы уровня модуля
    5. Переменные и функции уровня модуля
    6. Объект, который возвращает модуль
    7. Оператор возврата!

    Requires¶

    Общее¶

    • Все вызовы require должны находиться в верхней части файла, что делает зависимости статическими.
    • Requires должны быть отсортированы в алфавитном порядке по имени модуля.

    Структура запросов¶

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

    1. Определение общего предка.
    2. Блок всех импортированных пакетов.
    3. Блок для определений, полученных из пакетов, которые могут быть рекурсивно разбиты по подпапкам.
    4. Блок для модулей, импортированных из того же проекта, который может быть рекурсивно разбит по подпапкам.

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

    Требование библиотек¶

    Библиотеки – это проекты, которые определяют API для использования внешними потребителями, обычно путем предоставления таблицы верхнего уровня, которая требует других модулей. Библиотеки обычно предоставляют структурированный публичный API, составленный из внутренних модулей. Это позволяет библиотекам иметь стаб

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

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

    Реализация классов, основанных на прототипах

    Защита от опечаток

    Классы, основанные на прототипах¶

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

    Сначала мы создадим обычную пустую таблицу:

    Затем мы присваиваем член __index класса обратно самому себе. Это удобный трюк, который позволяет нам использовать таблицу класса в качестве метатела для экземпляров.

    • Когда мы создадим экземпляр, мы скажем Lua использовать наше значение __index для поиска значений, отсутствующих в наших экземплярах. Это похоже на прототип в JavaScript, если вы с ним знакомы.
    • В большинстве случаев мы создаем конструктор по умолчанию для нашего класса. По традиции мы обычно называем его new.

    Методы, которые не работают с экземплярами нашего класса, обычно определяются с помощью точки ( . ) вместо двоеточия ( : ).

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

    На этом этапе наш класс готов к использованию!

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

    Дальнейшие дополнения вы можете вносить в свой класс по мере необходимости:

    Ввести метаметод __tostring, чтобы облегчить отладку.

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

    Добавьте метод для проверки типа данного экземпляра, например:

    Защита от опечаток¶

    Индексирование в таблице в Lua дает nil, если ключ отсутствует, что может привести к ошибкам, которые трудно отследить!

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

    • Поскольку __index вызывается только тогда, когда в таблице отсутствует ключ, MyEnum.A и MyEnum.B по-прежнему будут возвращать вам ожидаемые значения, но MyEnum.FROB будет отбрасываться, что, надеюсь, поможет инженерам легче отследить ошибки.
    • Общая пунктуация¶

    Не используйте точки с запятой ; . Они обычно полезны только для разделения нескольких утверждений на одной строке, но вы не должны размещать несколько утверждений на одной строке в любом случае.

    Пробелы¶

    Отступ с помощью табуляции.

    Не допускайте ширины строк менее 100 колонок, предполагая ширину табуляции в четыре колонки.

    Luacheck не точен с символами табуляции, поэтому лучше использовать вместо него StyLua.

    Это отличается от обычного кода; надежда на то, что короткие строки помогают улучшить читаемость прозы комментариев, но слишком ограничивают код.

    • Если в вашем редакторе есть функция автообрезки, включите ее!

    Никакого вертикального выравнивания!

    • Вертикальное выравнивание усложняет редактирование кода и часто портится последующими редакторами.
    • Используйте одну пустую строку для выражения групп, когда это полезно. Не начинайте блоки с пустой строки. Лишние пустые строки ухудшают читабельность всего файла.
      • Используйте одно утверждение на строку. Размещайте тела функций на новых строках.
      • Это особенно актуально для функций, которые возвращают несколько значений. Сравните эти два утверждения:
      • Гораздо легче заметить ошибку (и гораздо труднее ее совершить), если функция не занимает одну строку.

      Это справедливо и для блоков if, даже если их тело – это просто оператор возврата.

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

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

      Ставьте пробел после каждой запятой в таблицах и вызовах функций.

      При создании блоков инлайнируйте все открывающие элементы синтаксиса.

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

      Новые строки в длинных выражениях¶

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

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

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

      Разбивайте таблицы типа словаря с более чем парой ключей на несколько строк.

      Разбивайте таблицы типа списка на несколько строк, если это имеет смысл.

      Обязательно соблюдайте ограничение на длину строки!

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

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

      Однако этот случай менее приемлем, если в смесь добавлены какие-либо не-таблицы. В этом случае следует использовать стиль, описанный выше.

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

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

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

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

      Для длинных условий в операторах if поместите условие в отдельную секцию с отступом и поставьте then на отдельной строке, чтобы отделить условие от тела if.

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

      Помните о различиях, особенно вокруг флагов. Удаление условия из середины строки делает различие гораздо менее читабельным, чем удаление его между двумя строками.

      • Для многострочных выражений if поместите then и else в начало новых строк с отступом в один раз.
      • Если выражение if не помещается на трех строках, преобразуйте его в обычный оператор if.
      • Исключение составляют случаи, когда выражение if находится в середине более крупного выражения (например, определение таблицы или вызов функции) и преобразование его в обычный оператор if потребует копирования большого количества строк.

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

      Хотя выражения if поддерживают elseif, его следует использовать редко. Если ваш набор условий достаточно сложен, чтобы потребовалось несколько elseif, то его может быть трудно прочитать как одно выражение. Когда использование выражения if, включающего elseif , предпочтительнее, поместите elseif (условие) then на новую строку так же, как then и else .

      Это компромисс. Было бы более последовательным поместить второе then на новую строку с отступом, но тогда вы получите глубокий отступ, что не очень хорошо.

      • Блоки¶

      Не используйте круглые скобки вокруг условий в блоках if, while или repeat. В Lua они не нужны!

      • Используйте блоки do, если необходимо ограничить область видимости переменной.

      Литералы¶

      При объявлении строковых литералов используйте двойные кавычки.

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

      Пустые строки легче определить с помощью двойных кавычек, поскольку в некоторых шрифтах две одинарные кавычки могут выглядеть как одна двойная кавычка ( “” против ”).

      Одинарные кавычки допустимы, если строка содержит двойные кавычки, чтобы уменьшить количество экранирующих последовательностей.

      • Если строка содержит как одинарные, так и двойные кавычки, предпочтительнее использовать двойные кавычки снаружи, но используйте свое лучшее суждение.

      Таблицы¶

      Избегайте таблиц с ключами, похожими на списки и словари.

      Итерация над такими смешанными таблицами вызывает затруднения.

      Это помогает прояснить, какую таблицу мы ожидаем увидеть в данном блоке кода!

      Добавьте запятые в конце многострочных таблиц.

      • Это позволяет нам пересортировать строки одним нажатием клавиши и делает различия чище при добавлении новых элементов.
      • Функции¶
      • Количество аргументов для данной функции должно быть небольшим, предпочтительно 1 или 2.
      • Всегда используйте круглые скобки при вызове функции. Lua позволяет пропускать их во многих случаях, но результаты, как правило, гораздо сложнее разобрать.

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

      • Объявляйте именованные функции, используя синтаксис префикса функции. Нечленимые функции всегда должны быть локальными.
        • При объявлении функции внутри таблицы используйте синтаксис function-prefix. Проведите различие между .
        • Используйте блочный комментарий перед функциями или объектами, чтобы описать их назначение.

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

        • Никаких комментариев к разделам.

        Комментарии, которые существуют только для того, чтобы разбить большой файл, – это запах кода; вероятно, вам нужно найти способ сделать ваш файл меньше, вместо того чтобы решать эту проблему с помощью комментариев секций. Комментарии, которые существуют только для обозначения уже очевидных групп кода (например, — VARIABLES — ) и слишком стилизованные комментарии могут сделать код более трудным для чтения, а не более легким. Кроме того, при написании заголовков разделов вы (и любой другой человек, редактирующий файл позже) должны быть внимательны, чтобы не запутать читателя вопросами о том, где заканчиваются разделы.

          Некоторые примеры способов разбиения файлов:

        Перенести внутренние классы и статические функции в собственные файлы, которые не включены в общедоступный API. Это также упрощает тестирование этих классов и функций.

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

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

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

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

        • Именование¶
          • Произносите слова полностью! Сокращения обычно делают код более легким для написания, но более трудным для чтения.

          Используйте имена PascalCase для классов и объектов типа enum.

          • Используйте PascalCase для всех API Roblox. API с camelCase в основном устарели, но пока еще работают.
          • Используйте имена в camelCase для локальных переменных, значений членов и функций.

          Для аббревиатур в именах не пишите все с заглавной буквы. Например, aJsonVariable или MakeHttpCall .

          • Исключение составляют случаи, когда аббревиатура представляет собой набор. Например, в anRGBValue или GetXYZ . В этих случаях RGB следует рассматривать как сокращение RedGreenBlue, а не как аббревиатуру.
          • Используйте имена LOUD_SNAKE_CASE для локальных констант.

          Префикс частных членов обозначайте подчеркиванием, например _camelCase .

          В Lua нет правил видимости, но использование такого символа, как подчеркивание, помогает выделить приватный доступ.

          Если ваш модуль экспортирует одну функцию с именем doSomething, файл должен иметь имя doSomething.lua.

          Yielding¶

          • Не вызывайте функции yielding в основной задаче. Оберните их в coroutine.wrap или delay, а также рассмотрите возможность раскрытия Promise или Promise-подобных async-функций.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *