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

Ripara 'attempt to compare number with nil' e 'arithmetic on a nil value' in FiveM: dati del giocatore non caricati, valori di config mancanti, tonumber e default sicuri con `or`.

Output della console:

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')

Una riga dello script usa un valore che non esiste ancora in un confronto o un calcolo. Ecco cosa solitamente lascia il valore vuoto, e come rendere lo script sicuro.

Cosa significa l'errore

Lua ti dà nil per qualsiasi variabile o voce di tabella che non ha valore. Confrontare (<, >, <=) o calcolare (+, -, *, /) con nil ferma lo script con uno di questi messaggi:

  • attempt to compare number with nil (o attempt to compare nil with number): un lato del confronto è nil.
  • attempt to perform arithmetic on a nil value: un calcolo usa una variabile nil. Quando Lua conosce il nome, lo aggiunge, come (field 'money') o (local 'price').

Il numero di riga nel messaggio è la riga con il confronto o la somma. nil è uno dei valori su quella riga. Stampali per vedere quale:

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

1. I dati del giocatore non sono caricati ancora

La causa più comune: lo script legge il giocatore prima che il framework abbia finito di caricarlo, ad esempio nelle prime righe di un file, o in un thread che si avvia immediatamente.

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

Aspetta l'evento caricato del framework, e leggi i dati da lì:

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)

Sul server, un oggetto giocatore può essere nil anche quando l'id è sbagliato o il giocatore se ne è andato. Controllalo prima di usarlo:

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

Su QBox, l'equivalente è exports.qbx_core:GetPlayer(source), con lo stesso controllo nil.

Consiglio: se lo script viene riavviato mentre sei sul server, playerLoaded ha già sparato e non sparerà di nuovo. Leggi i dati una volta anche quando la risorsa si avvia.

2. Un valore di config è mancante

Hai aggiunto una riga a config.lua che lo script non ha, o lo script legge una chiave che la tua config più vecchia non contiene. Dopo un aggiornamento, una vecchia config.lua è una causa molto comune.

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

Confronta la tua config con quella fornita con la nuova versione, e aggiungi le chiavi mancanti. Nel tuo codice, dai ad ogni impostazione un default:

lua
local price = Config.Price or 100

3. Il valore è una stringa, non un numero

I valori da un database, una casella di input in un menu o un messaggio JSON spesso arrivano come testo. Confrontare una stringa con un numero dà un errore diverso (attempt to compare number with string), ma una conversione che fallisce ti dà nil, il che riporta questo errore indietro. tonumber converte, e restituisce nil quando non può:

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

4. Usa or per un default

or restituisce il lato destro quando il lato sinistro è nil (o false). È il modo più breve per rendere un calcolo sicuro:

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

Usalo dove un valore mancante può davvero significare zero, come un bonus opzionale. Dove un valore mancante è un bug, ad esempio un prezzo che deve esistere, fermarsi con un messaggio chiaro invece di nasconderlo:

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. Un risultato di database o callback è vuoto

Una query che non trova alcuna riga dà nil o una tabella vuota. Leggere una colonna da essa fallisce:

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

Controlla la riga per prima:

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

Lo stesso vale per callback server: la risposta può essere nil se il callback non è stato trovato o non ha restituito nulla. Se il tuo script aspetta su un callback, gestisci quel caso. Correlato: attempt to call a nil value è l'errore gemello quando una funzione, non un valore, è mancante.

6. Un errore di digitazione in un nome di field

xPlayer.money e xPlayer.Money sono diversi. Lo sono anche price e Price. Il messaggio di errore spesso chiama il field: controlla la sua ortografia rispetto alla documentazione del framework o rispetto alla tabella che stampi con print(json.encode(data)).

Elenco di controllo

Sintomo Correzione
Errore subito dopo l'unione Aspetta l'evento giocatore caricato prima di leggere i dati del giocatore
xPlayer o Player è nil sul server Controlla if not xPlayer then return end e l'id di sorgente
Errore dopo aver aggiornato uno script Aggiungi le nuove chiavi della config.lua fornita alla tua
Il valore proviene da un menu o JSON Converti con tonumber(value) e controlla che non sia nil
Un valore potrebbe mancare di proposito Usa value or 0 come default
La query del database non restituisce nulla Controlla che la riga non sia nil prima di leggere le sue colonne
Il field è nil anche se dovrebbe esistere Controlla l'ortografia e le maiuscole

Risposte rapide

Cosa significa 'attempt to compare number with nil'?

Una riga confronta un numero con qualcosa che non ha valore, come price > 100 quando price è nil. Trova quale variabile è nil e perché non è mai stata impostata.

Come do a una variabile un valore predefinito in Lua?

Usa or: local count = tonumber(value) or 0. Se il valore è nil o non è un numero, count diventa 0.

Perché succede solo subito dopo che mi unisco al server?

Lo script legge i dati del giocatore prima che il framework li abbia caricati. Aspetta l'evento giocatore caricato, o controlla che l'oggetto giocatore non sia nil prima di leggerlo.

Script senza questo problema

Shop CreatorCrea un negozio in meno di un minuto — proprietari, dipendenti, casseforti e rapine inclusi.Vedi script →Pawn Shop AppUn banco dei pegni tra giocatori dentro lb-phone.Vedi script →Quest CreatorUn editor visuale di missioni e dialoghi con gli NPC, costruito nodo per nodo in gioco.Vedi script →

Continua a leggere