Yritän koodailla Computercraftissa Minecrafiin DNS-palvelinta tai vastaavaa ja tulee virhettä, kun suoritan tämän koodin:
function dns_load(filu) -- lataa dns-tietokanta file = io.open(filu, "r") while true do line = file.read(file) table.insert(db, line) j = j + 1 if not line then break end end end function dns_search(query) -- etsi dns-tietokannasta repeat if(string.find(db[i], query)) then tietue = db[i] loytyi = 1 end i = i + 1 until loytyi == 1 return tietue end function split(string, delimiter) local result = { } local from = 1 local delim_from, delim_to = string.find( string, delimiter, from ) while delim_from do table.insert( result, string.sub( string, from , delim_from-1 ) ) from = delim_to + 1 delim_from, delim_to = string.find( string, delimiter, from ) end table.insert( result, string.sub( string, from ) ) return result end j = 1 loytyi = 0 i = 1 db = { } dns_load("dns.txt") rednet.open("top") while true do viesti = rednet.receive(60) viestihajotettu = split(viesti, "!") -- id!osoite lahettaja = viestihajotettu[1] -- 22 muuttuja = viestihajotettu[2] -- esim. google.com rikottu = split(dns_search(muuttuja), "!") osoite = rikottu[1] ip = rikottu[2] rednet.send(lahettaja, ip, true) end rednet.close("top")
dns:29: attempt to index ? (a nil value)
dns.txt tiedostossa lukee esim:
google.com!22
Asiakasohjelman testiversion koodi:
rednet.open("right") my_id = os.computerID() rednet.broadcast(my_id .. "!google.com") print(rednet.receive(60)) rednet.close("right")
Miten saan virheen poistumaan ja ohjelman toimimaan?
Luetko edes virheilmoituksia, vai etsitkö aina vikaa summanmutikassa? Tuossahan lukee selvästi, että dns-nimisen jutun rivillä 29 yritetään indeksoida jotain, jonka arvo on nil. Kyseessä on nähtävästi split-funktion kolmas rivi, jossa kohdassa string.find on muuttuja string ja indeksi find. Näin ollen tiedetään, että virheilmoituksen syy on, että string-muuttujassa on arvo nil.
Älä käytä itse string-nimisiä muuttujia, koska string-muuttujassa ovat jo Luan tekstinkäsittelyfunktiot. Kun sijoitat string-muuttujaan jonkin vääränlaisen arvon, string.find ei enää toimi. Sen sijaan jos muuttujasi nimi olisi vaikka s, string.find toimisi oikein s-muuttujan arvosta riippumatta.
Kun vaihdat parametrin nimen, saat toisen virheilmoituksen: "bad argument #1 to 'find' (string expected, got nil)". Tämä tietenkin johtuu siitä, että parametrin arvo on edelleen nil ja nyt se syötetään funktiolle string.find. Yksi mahdollinen ratkaisu on tarkistaa split-funktion alussa, että parametri ei ole nil. Toinen ratkaisu on selvittää, mistä nil-arvo tulee, ja korjata asia.
Puolustaudun sillä, että latasin split-funktion suoraan netistä koskematta siihen ja aloin tutustumaan Luaan vasta eilen. :D
Lisäsin split-funktioon tarkistuksen, että stringi (muutin muuttujan string nimeksi stringi) ei ole nil niin se jatkaa koodia ja nyt se valittaa rivillä 58 samaa vikaa eli " attempt to index ? (a nil value)" vaikka sen ei pitäisi olla nil. Nähtävästi se asiakasohjelma lähettää palvelimelle vain asiakasohjelman tietokoneen id:n eli muuttujan lahettaja, mutta ei sitä tietoa joka tulisi muuttujaan muuttuja.
Tämän siis huomaa siitä kun tulostaa muuttujan viesti niin se tulostaa vain tietokoneen ID-numeron vaikka sen pitäisi tulostaa jotain tyyliin "23!google.com". Ilmeisesti alkuperäinenkin vika johtui juurikin tästä.
"Rivi 58" ei kerro paljonkaan, kun kerran koodisi on muuttunut (ja ennen tuolla rivillä luki vain end). Oletan kuitenkin, että virhe liittyy split-funktion palauttamiin arvoihin.
Jos muutit split-funktiota niin, että se nil-syötteellä palauttaa nil-tuloksen, tietenkin pitää myös muuttaa split-funktion kutsumisen jälkeistä koodia niin, että se nil-tuloksen (tai myös 1-alkioisen taulun) kohdatessaan tekee jotain järkevää eikä yritä väkisin lukea siitä kahta arvoa.
Pahoittelen. Rivillä 58 on siis:
osoite = rikottu[1]
Eli viesti = rednet.receive(60) odottaa 60s ajan viestejä ja sen kuuluisi saada viesti "23!google.com" asiakasohjelmalta, jossa 23 tarkoittaa asiakkaskoneen id:tä ja perässä oleva osoite google.com sitä minkä id:n asiakaskone haluaa tietää, jolloin palvelimen pitäisi hakea google.comin id ja palauttaa se asiakaskoneella. Tämä ei onnistu, koska viesti-muuttujassa lukee vain "23".
EDIT: Virhe korjattu ja toimii!
Mikä oli virhe?
Metabolix kirjoitti:
Mikä oli virhe?
viesti = rednet.receive(60)
Korjattuna:
senderId, viesti, distance = rednet.receive(60)
Nähtävästi rednet.receive lähettää sen lähettäjäkoneen ID:n ja alkuperäisessä koodissa muuttuja viesti saa pelkästään sen lähettäjäkoneen ID:n. Korjatussa versiossa lähettäjäkoneen ID sisältyy jo muuttujaan senderId, joten sen lähettäminen viestin seassa on turhaa.
Aihe on jo aika vanha, joten et voi enää vastata siihen.