Разработка / ROBLOX
Настройка false в Luau: почему значение по умолчанию включило музыку снова
Разберите оригинальный пример настройки музыки: сохранённое false должно остаться выключенным, а отсутствующее значение может получить заранее выбранный вариант. Проверьте различия nil, false, чисел и строк до подключения интерфейса или сохранений.
Сначала определите смысл каждого значения #
Представьте вымышленную игру с прогулкой по острову и отдельной настройкой фоновой музыки. Игрок выключил музыку, поэтому в учебных данных находится false. У нового игрока настройка ещё не задана: это nil. Автор хочет включать музыку по умолчанию только во втором случае. Такая договорённость отделяет явный выбор от отсутствующей информации; без неё две ситуации легко перепутать.
Пример не утверждает, что музыка или такая настройка уже реализованы в наших играх. Мы сначала проверяем небольшую функцию с обычными значениями Luau. Здесь нет DataStore, кнопки, Sound или сетевого запроса. После проверки алгоритма эти части потребуется подключить отдельно и повторить испытания в Studio. Начните с таблицы: true означает включено, false означает выключено, nil означает значение не получено.
Воспроизведите ошибку с or #
Строка savedMusic or true кажется удобным способом выбрать значение по умолчанию. Но оператор or не проверяет исключительно отсутствие данных. По документации Luau он выбирает первый операнд, если тот считается истинным, иначе второй. Для savedMusic=false получится true. В результате выключенная настройка превращается во включённую, хотя значение было явно задано.
Сначала выполните короткий пример со значением false и выведите результат. Затем повторите с true и nil. Получатся разные случаи: true сохраняется, false заменяется, nil заменяется. Это поведение языка, а не ошибка загрузки данных. Не исправляйте проблему повторной записью в хранилище до проверки выражения: неверный запасной вариант может исказить правильные входные данные уже после чтения.
local savedMusic = false
print(savedMusic or true)
print(0 or 9)
print(true and false or true)Не считайте ноль и пустую строку выключением #
В Luau только false и nil являются ложными при такой оценке. Число 0 и пустая строка считаются истинными. Поэтому выражение 0 or 9 вернёт 0, а пустая строка or текст по умолчанию сохранит пустую строку. Если интерфейс показывает пустую подпись, один оператор or не обязательно подставит ожидаемое сообщение.
Для нашей настройки это не повод принимать 0 как правильное выключенное состояние. Договорённость разрешает только boolean, а не произвольное значение с подходящей истинностью. Строка "false" тоже не равна логическому false. Запишите эти случаи как неправильные входы. Не превращайте непонятные данные в предпочтение игрока только потому, что условие if их пропускает.
Заменяйте только nil явной проверкой #
В функции booleanPreference сначала проверяется raw==nil. Только эта ветка возвращает заранее выбранный defaultValue. Если значение присутствует, функция отдельно проверяет type(raw)=="boolean". Настоящие true и false передаются дальше без изменения. Число или строка дают отказ, а не молчаливую замену. Так недостающий выбор отличается и от выключения, и от некорректных данных.
Для этого упражнения defaultValue сам должен быть логическим значением; проверка assert отмечает ошибку вызова функции автором. Она не заменяет обработку произвольных данных в рабочем интерфейсе. При интеграции заранее решите, где хранится допустимый вариант по умолчанию и что делает приложение при отказе. Учебный код не должен неожиданно выбирать его из случайного пользовательского текста.
local function booleanPreference(raw, defaultValue)
assert(type(defaultValue) == "boolean")
if raw == nil then
return defaultValue, true
end
if type(raw) ~= "boolean" then
return nil, false
end
return raw, true
end
local value, valid = booleanPreference(false, true)
print(value, valid)
value, valid = booleanPreference(nil, false)
print(value, valid)
value, valid = booleanPreference("false", true)
print(value, valid)Разделите значение и признак успеха #
Функция возвращает два результата: предпочтение и признак valid. Выключение — это false,true: значение корректно, музыка не нужна. Отказ — nil,false: вход не соответствует договорённости. Проверять успех только по первому результату нельзя, потому что корректное false тогда попадёт в ту же ветку, что и отказ. Сначала проверьте valid, затем применяйте value.
Например, будущий обработчик кнопки может получить false,true и обновить состояние выключенной музыки. При nil,false он должен выполнить заранее предусмотренную обработку ошибки, а не включать звук. Статья не выбирает за вас поведение рабочего продукта: можно сохранить прежнее подтверждённое состояние и сообщить о проблеме. Главное — не выдавать отказ за сделанный игроком выбор.
Осторожно с конструкцией and/or #
Выражение condition and selectedValue or fallback иногда используют как короткий выбор одного из двух значений. Для логического selectedValue=false оно опасно: даже при condition=true промежуточный результат будет false, и or выберет fallback. В нашем случае true and false or true снова даёт true. Такая сокращённая запись не сохраняет все допустимые результаты.
Используйте явную ветку, если выбранный результат может быть false или nil. Краткость сама по себе не доказывает правильность. В проверке оставьте случай с истинным условием и ложным выбранным значением: он ловит ошибку, которую пример только с true не показывает. В статье о порогах мы выбирали первую подходящую числовую ветку; здесь задача другая — сохранить значение, которое язык считает ложным.
Выполните матрицу входов #
Проверьте три корректных случая отдельно: false при defaultValue=true остаётся false,true; true при defaultValue=false остаётся true,true; nil при defaultValue=true даёт true,true. Добавьте обратный вариант отсутствующего значения с выключенным вариантом по умолчанию. Ожидания нужно записать до выполнения, иначе случайно полученное включение легко принять за норму.
Затем передайте 0, пустую строку, строку "false" и число 1. Все они должны дать nil,false по нашей договорённости. Проверяйте оба результата, а не только отсутствие аварии. Исходный набор assertions реально выполнен отдельным интерпретатором Luau; это подтверждает перечисленные операции с данными. Он не подтверждает звучание музыки, нажатия кнопок или работу сохранения в Roblox.
| Вход | Результат |
|---|---|
| false | false, true |
| true | true, true |
| nil | defaultValue, true |
| 0 / "false" | nil, false |
Подключайте интерфейс отдельным этапом #
Когда функция работает, составьте план интеграции: откуда приходит значение, когда выполняется чтение и какое подтверждённое состояние получает интерфейс. При повторном открытии панели выключенное предпочтение должно остаться выключенным. При отсутствии значения нужно применить согласованный вариант один раз в рамках выбранного сценария. Повторный рендер не должен превращаться в новую трактовку false.
Не распространяйте результат чистого теста на DataStore или сервер. Ошибка загрузки, отсутствие записи и отклонённый тип могут требовать разных действий. Серверная проверка входов и надёжная обработка ошибок остаются отдельными задачами. Не записывайте случайный запасной вариант поверх данных только из-за того, что интерфейс открылся раньше завершения чтения.
Сохраните понятную запись для другого разработчика #
В заметке укажите допустимые типы, смысл nil, оба возвращаемых значения и случаи отказа. Добавьте исходники и точный результат проверки. Это полезнее сообщения «починил музыку»: другой разработчик сможет повторить проверку без доступа к вашей игровой сессии. Используйте вымышленные значения, не помещайте в пример реальные идентификаторы игроков или доступы.
Если позже договорённость изменится, обновите функцию, ожидаемые результаты и объяснение вместе. Например, разрешение отдельного строкового режима требует явного преобразования и нового набора проверок, а не удаления проверки типа. Сохраняйте различие между авторским решением продукта и поведением операторов языка: документация объясняет второе, а первое задаётся вашим проектом.
Проверьте итог перед передачей #
Успешный результат упражнения — сохранённое false остаётся false, nil получает только согласованный вариант, а неподходящие типы дают отдельный отказ. Проверьте это с обоими вариантами defaultValue и при повторном вызове. Убедитесь, что вызывающий код смотрит на признак valid. Проверьте отсутствие сокращённой and/or-замены там, где допустим false.
После интеграции повторите проверку настоящей панели в Studio и отдельно проверьте сохранение и повторное чтение. Пока это только план будущих испытаний. Оригинальный учебный пример и официальный источник помогают разобраться в причине ошибки, но не означают, что существующая игра уже изменена. Подтверждённый результат чистой функции и результат в игре фиксируйте отдельно.
| Проверка | Действие |
|---|---|
| Тип | boolean |
| Отсутствие | Отдельная ветка nil |
| Результат | value и valid отдельно |
| Интеграция | Проверить в Studio |