attempt to compare number with nil / arithmetic on a nil value: naprawa

Napraw 'attempt to compare number with nil' i 'arithmetic on a nil value' w FiveM: niezaładowane dane gracza, brakujące wartości config, tonumber i bezpieczne domyślne z `or`.

Wyjście konsoli:

text
SCRIPT ERROR: @my_script/server/main.lua:58: attempt to compare number with nil
SCRIPT ERROR: @my_script/client/main.lua:91: attempt to perform arithmetic on a nil value (field 'money')

Linia skryptu używa wartości, która nie istnieje jeszcze w porównaniu lub obliczeniu. Oto, co zwykle pozostawia wartość pustą i jak uczynić skrypt bezpiecznym.

Co błąd oznacza

Lua daje ci nil dla każdej zmiennej lub wpisu tabeli, który nie ma wartości. Porównywanie (<, >, <=) lub obliczanie (+, -, *, /) z nil zatrzymuje skrypt z jedną z tych wiadomości:

  • attempt to compare number with nil (lub attempt to compare nil with number): jedna strona porównania to nil.
  • attempt to perform arithmetic on a nil value: obliczenie używa zmiennej nil. Gdy Lua zna nazwę, ją dodaje, takie jak (field 'money') lub (local 'price').

Numer linii w wiadomości to linia z porównaniem lub sumą. nil to jeden z wartości na tej linii. Wydrukuj je, aby zobaczyć, która:

lua
print('price', price, type(price))
print('count', count, type(count))
if price > count then
    -- ...
end

1. Dane gracza nie są jeszcze załadowane

Najczęstsza przyczyna: skrypt czyta gracza, zanim framework skończy ich ładować, na przykład w pierwszych liniach pliku, lub w wątku, który startuje od razu.

lua
-- runs too early on the client: money is nil
local money = ESX.GetPlayerData().money
if money > 100 then
    -- ...
end

Czekaj na zdarzenie załadowanego frameworku i przeczytaj dane stamtąd:

lua
-- ESX client
local PlayerData = {}

RegisterNetEvent('esx:playerLoaded', function(xPlayer)
    PlayerData = xPlayer
end)
lua
-- QBCore client
local QBCore = exports['qb-core']:GetCoreObject()
local PlayerData = {}

RegisterNetEvent('QBCore:Client:OnPlayerLoaded', function()
    PlayerData = QBCore.Functions.GetPlayerData()
end)

Na serwerze, obiekt gracza może również być nil, gdy identyfikator jest zły lub gracz odszedł. Sprawdzaj to, zanim go użyjesz:

lua
local xPlayer = ESX.GetPlayerFromId(source)
if not xPlayer then return end
lua
local Player = QBCore.Functions.GetPlayer(source)
if not Player then return end

Na QBox, równoważny to exports.qbx_core:GetPlayer(source), z tą samą kontrolą nil.

Porada: jeśli skrypt jest restartowany, gdy jesteś na serwerze, playerLoaded już się uruchomił i nie uruchomi się ponownie. Przeczytaj dane raz, gdy zasób się uruchomi też.

2. Brakuje wartości config

Dodałeś linię do config.lua, którą skrypt nie ma, lub skrypt czyta klucz, którego starsza konfiguracja nie zawiera. Po aktualizacji, stary config.lua jest bardzo częstą przyczynę.

lua
-- config.lua of the old version has no Config.Price
if playerMoney >= Config.Price then
    -- ...
end

Porównaj konfigurację z tą dostarczoną z nową wersją i dodaj brakujące klucze. W swoim własnym kodzie daj każdemu ustawieniu wartość domyślną:

lua
local price = Config.Price or 100

3. Wartość jest stringiem, a nie liczbą

Wartości z bazy danych, pola wprowadzania w menu lub wiadomości JSON często przychodzą jako tekst. Porównywanie stringa z liczbą daje inny błąd (attempt to compare number with string), ale konwersja, która zawiedzie, daje ci nil, co przynosi ten błąd z powrotem. tonumber konwertuje i zwraca nil, gdy nie może:

lua
local amount = tonumber(data.amount)
if not amount then
    return -- not a number: stop here
end

4. Użyj or dla domyślnego

or zwraca prawą stronę, gdy lewa strona to nil (lub false). To najkrótszy sposób na uczyninie obliczenia bezpiecznym:

lua
local count = tonumber(data.count) or 0
local total = (item.price or 0) * count

Użyj go, gdzie brakująca wartość rzeczywiście może oznaczać zero, takie jak opcjonalny bonus. Gdzie brakująca wartość to błąd, na przykład cena, która musi istnieć, zatrzymaj się z jasną wiadomością zamiast go ukrywać:

lua
local price = Config.Items[name] and Config.Items[name].price
if not price then
    print(('no price set for %s'):format(name))
    return
end

5. Wynik bazy danych lub callbacku jest pusty

Zapytanie, które nie znajdzie wiersza, daje nil lub pustą tabelę. Czytanie kolumny z niej zawodzi:

lua
local row = MySQL.single.await('SELECT balance FROM bank WHERE owner = ?', { identifier })
if row.balance > 0 then   -- row is nil when the player has no row
    -- ...
end

Najpierw sprawdzaj wiersz:

lua
local row = MySQL.single.await('SELECT balance FROM bank WHERE owner = ?', { identifier })
local balance = row and row.balance or 0

To samo dotyczy callbacków serwera: odpowiedź może być nil, jeśli callback nie został znaleziony lub nic nie zwrócił. Jeśli twój skrypt czeka na callback, obsłuż ten przypadek. Powiązane: attempt to call a nil value to siostrze błąd, gdy funkcja, a nie wartość, brakuje.

6. Literówka w nazwie pola

xPlayer.money i xPlayer.Money są różne. Podobnie price i Price. Wiadomość błędu często wymienia pole: sprawdzaj jego pisownię względem dokumentacji frameworku lub względem tabeli, którą wydrukujesz za pomocą print(json.encode(data)).

Lista kontrolna

Objaw Naprawa
Błąd zaraz po dołączeniu Czekaj na zdarzenie gracza załadowanego przed przeczytaniem danych gracza
xPlayer lub Player jest nil na serwerze Sprawdzaj if not xPlayer then return end i identyfikator źródła
Błąd po aktualizacji skryptu Dodaj nowe klucze dostarczonego config.lua do swojego
Wartość pochodzi z menu lub JSON Konwertuj za pomocą tonumber(value) i sprawdzaj, czy nie jest nil
Wartość może brakować celowo Użyj value or 0 jako domyślnego
Zapytanie bazy danych zwraca nic Sprawdzaj wiersz nie jest nil przed przeczytaniem jego kolumn
Pole jest nil, chociaż powinno istnieć Sprawdzaj pisownię i wielkie litery

Szybkie odpowiedzi

Co oznacza 'attempt to compare number with nil'?

Linia porównuje liczbę z czymś, co nie ma wartości, takie jak price > 100, gdy price jest nil. Znajdź, której zmiennej jest nil i dlaczego nigdy nie została ustawiona.

Jak dać zmiennej domyślną wartość w Lua?

Użyj or: local count = tonumber(value) or 0. Jeśli wartość to nil lub nie jest liczbą, count staje się 0.

Dlaczego zdarza się to tylko zaraz po dołączeniu do serwera?

Skrypt czyta dane gracza, zanim framework je załadował. Czekaj na zdarzenie gracza załadowanego lub sprawdź, czy obiekt gracza nie jest nil przed przeczytaniem z niego.

Skrypty bez tego problemu

Shop CreatorZbuduj sklep w niecałą minutę — właściciele, pracownicy, sejfy i napady w zestawie.Zobacz skrypt →Pawn Shop AppLombard między graczami wewnątrz lb-phone.Zobacz skrypt →Quest CreatorWizualny edytor questów i dialogów z NPC, budowanych węzeł po węźle w grze.Zobacz skrypt →

Czytaj dalej