2013-10-10 14 views
7

Sto imparando Lua da un libro e NON sono un programmatore. Sto cercando di salvare una tabella di dati in un file utilizzando le seguenti funzioni (che sono state copiate direttamente dal libro), ma la funzione sta ricevendo un errore quando si tenta di ottenere una stringa da _G [resTable]. Perché?Lua: Quando e come scrivere tabelle su _G

function readFromFile(filename,resTable) 
    local hfile = io.open(filename) 
    if hfile == nil then return end 
    local results = {} -why is this table here? 
    local a = 1 
    for line in hfile:lines() do-- debug shows this loop doesn't run (no lines in hfile?) 
     _G[resTable[a]] = line 
     a = a + 1 
    end 
end 

function writeToFile(filename, resTable) 
    local hfile = io.open(filename, "w") 
    if hfile == nil then return end 
    local i 
    for i=1, #resTable do 
     hfile:write(_G[resTable[i]])--bad argument #1 to 'write' (string expected, got nil) 
    end 
end 

'writeToFile" ottiene un errore quando si cerca di:. Scrivere a _G [resTable [i]] Nelle due precedenti funzioni elencate qui, non capisco il motivo per cui fanno riferimento _G [resTable [i] .] poiché non vedo alcun codice che sta scrivendo per _G

Così qui è l'ordine di esecuzione:

local aryTable = { 
"Score", 
"Lives", 
"Health", 
} 

readFromFile("datafile", aryTable) 

writeToFile("datafile", aryTable) 

ed ottengo un errore:

bad argument #1 to 'write' (string expected, got nil) 
stack traceback: 
[C]: in function 'write' 
test.lua:45: in function 'writeToFile' 
test.lua:82: in main chunk 
+0

Che cosa contiene il file di dati? – interjay

+0

attualmente "datafile" non ha nulla – PHazer

+0

... quindi cosa ci si aspetta da 'readFromFile'? – interjay

risposta

0

Queste non sono funzioni di "lettura/scrittura di tabelle da/a qualsiasi file" generalizzate. Apparentemente si aspettano il nome di una tabella globale come argomento, non una tabella di riferimento a un locale. Sembrano il tipo di soluzione una tantum a un problema molto specifico che tende a comparire nei libri. :-)

Le tue funzioni non dovrebbero fare nulla con _G. Non ho un riferimento API a portata di mano, ma il ciclo di lettura dovrei fare qualcosa di simile

resTable[a] = line 

e il ciclo di scrittura farei

hfile:write(resTable[i]) 

buttare fuori che i "risultati" locali tavolo troppo. :-)

+0

Sì, le funzioni si aspettano il nome di una tabella globale come argomento. Questo è il motivo per cui mi confonde il motivo per cui l'autore ha chiamato le funzioni mentre passava invece una tabella locale come argomento. – PHazer

+0

... e la misteriosa tabella dei "risultati" non mi ha infuso alcuna fiducia. – PHazer

+1

Il ragionamento dell'autore dietro "readFromFile": _Nella vostra app, il numero di variabili che potreste memorizzare potrebbe essere diverso per ogni applicazione. Non saprete mai l'ordine in cui i vostri dati sono salvati, e se l'ordine di salvataggio dei dati o leggendo i dati è cambiato, potresti avere valori che finiscono nelle variabili sbagliate. Quindi, ciò che faremo per risolvere questo problema è avere una tabella con i dati e i nomi archiviati. Questo ci fornirà la flessibilità per ampliarlo ulteriormente in futuro. Quindi mostra la funzione 'readFromFile'. – PHazer

0

Questo codice legge e scrive i dati da un file in variabili globali i cui nomi sono specificati in aryTable. Poiché il tuo file è vuoto, readFromFile non imposta effettivamente i valori delle variabili. E quindi writeToFile non riesce quando si tenta di ottenere i valori delle variabili, perché non sono stati impostati.

provare a mettere i dati nel file in modo che le variabili ottengono impostate, o impostare la variabile di valori da soli prima di scrittura nel file (ad esempio Score = 10, etc.)

+0

Hai identificato il mio problema principale con la scrittura dell'autore. Mi sembrava ovvio che ci fosse un problema con 'readFromFile' su un file di dati vuoto, ma in nessun punto del capitolo menzionava alcun modo di registrare dati nel file di dati al di fuori dell'uso di' writeToFile'. – PHazer

+0

Inoltre, quando inserisco alcune righe di dati nel file di dati direttamente (editor di testo), la funzione le cancella tutte in ogni caso. – PHazer

3

A quanto pare l'autore ha messo in atto un modo di salvare un elenco di variabili globali da archiviare e ripristinare.

La funzione writeToFile prevede un nome file e un elenco di nomi di variabili globali (resTable). Poi si apre un nome file per la scrittura e itera sui nomi forniti:

for i=1, #resTable do 
    hfile:write(_G[resTable[i]]) 
end 

in questo ciclo resTable[i] è il nome i-esimo e _G[resTable[i]] è il valore corrispondente, preso dalla tabella _G, che memorizza tutte le variabili globali . Se un globale con quel nome non è definito, _G[resTable[i]] restituirà nil, che è la causa dell'errore riscontrato. Pertanto, è necessario fornire un numero resTable riempito con nomi di valori globali esistenti per evitare questo errore.

Oltre a ciò, la strategia di serializzazione dell'autore è davvero ingenua, poiché gestisce solo le variabili con valori stringa.Infatti salvando le variabili in un file come quello si perde l'informazione sul tipo, quindi una variabile avente il valore "100" (una stringa) e un'altra con il valore 100 (un numero) verranno memorizzate sullo stesso disco.

Il problema è evidente analizzando la funzione readFromFile. Dopo aver aperto il file per la lettura, la scansione riga per riga, la creazione di una nuova variabile per ogni nome citato nella sua lista resTable:

local a = 1 
for line in hfile:lines() do 
    _G[resTable[a]] = line 
    a = a + 1 
end 

il problema è molteplice:

  • il ciclo variabile line volontà hanno sempre un valore stringa, quindi le globali ricreate saranno tutte stringhe, anche se originariamente erano numeri;
  • presuppone che le variabili vengano ricreate nello stesso ordine, pertanto è necessario fornire gli stessi nomi in resTable utilizzati quando si è salvato il file;
  • presuppone che i valori siano memorizzati uno per riga, ma questa è una falsa ipotesi, poiché la funzione writeToFile non scrive un carattere di fine riga dopo ogni valore;

Inoltre che local results = {} è inutile e in entrambe le funzioni il file handle hfile non è chiuso. Quest'ultima è una pratica molto scorretta: potrebbe sprecare risorse di sistema e se il tuo script fallisce, parte dei dati presumibilmente scritti non potrebbero mai arrivare al disco, poiché potrebbe essere ancora bloccato in qualche buffer. Gli handle di file si chiudono automaticamente al termine dello script, ma solo se termina in modo corretto.

A meno che non abbiate commesso qualche errore nell'incollare il codice o omesso parti significative di esso o che il libro stia costruendo qualche esempio in modo incrementale, oserei dire che è piuttosto schifoso.


Se volete un modo rapido e sporco per salvare e recuperare alcune variabili globali è possibile utilizzare questo:

function writeToFile(filename, resTable) 
    local hfile = io.open(filename, "w") 
    if hfile == nil then return end 
    for _, name in ipairs(resTable) do 
     local value = _G[name] 
     if value ~= nil then 
      hfile:write(name, " = ") 
      local vtype = type(value) 
      if vtype == 'string' then 
       hfile:write(string.format("%q", value)) 
      elseif vtype == 'number' or vtype == 'boolean' then 
       hfile:write(tostring(value)) 
      else 
       -- do nothing - unsupported type 
      end 
      hfile:write("\n") 
     end 
    end 
    hfile:close() 
end 

readFromFile = dofile 

Si risparmia le variabili globali come uno script Lua e li rilegge eseguendo lo script utilizzando Lua dofile funzione. Il suo limite principale è che può solo salvare stringhe, booleane un numero, ma di solito questo è sufficiente durante l'apprendimento.

È possibile verificare con le seguenti affermazioni:

a = 10 
b = "20" 
c = "hello" 
d = true 
print(a, b, c, d) 
writeToFile("datafile", { "a", "b", "c", "d" }) 
a, b, c, d = nil 
print(a, b, c, d) 
readFromFile("datafile") 
print(a, b, c, d) 

Se avete bisogno di tecniche di serializzazione più avanzate è possibile fare riferimento a Lua WIKI page on table serialization.

+0

Devo dire che nel paragrafo successivo del suo libro, ammette, _Se i dati da salvare sono nient'altro, _ (oltre alle stringhe o ai numeri) _ le funzioni inizieranno a fallire, e ancor più se la variabile è una tabella . Il problema più grande con le tabelle è l'iterazione attraverso le profondità della tabella. Si impegna quindi a utilizzare la libreria JSON per codificare o decodificare le informazioni tra l'oggetto tabella e una stringa codificata JSON. – PHazer

+0

Anche l'autore lavora in modo incrementale attraverso problemi con le funzioni più semplici per risolvere il problema, evidenziando le insidie, quindi introducendo funzioni più complete man mano che il capitolo avanza. Questo può o no essere il motivo per cui queste funzioni hanno problemi così come sono. La sua soluzione definitiva è una funzione che salva le tabelle come stringhe codificate JSON. Eppure, per un principiante come me questo approccio tende a confondere. – PHazer

+0

@PHazer Non posso giudicare senza vederlo, ma odio i libri che semplificano eccessivamente le cose: tendono a rendere più difficile l'apprendimento perché il lettore, specialmente il novizio, alla fine deve disimparare cattive abitudini o falsi approcci. –