Solidity Bits - salvestusruum vs mälu

Fotokrediit

Soliditys kodeerimine pole alati intuitiivne, kuid see on lõbus. Üks väikestest väljakutsetest, mis mul pea ümber pidi mässima, oli erinevus salvestuse ja mälu vahel.

Kujutage ette lihtsat näidet nagu allpool

pragma tugevus ^ 0,4,22;
leping Viljad {
    nöörid [] avalikud esemed;
    ehitaja () avalik {
        üksused.push ('õun');
        üksused.push ('oranž');
    }
}

Kui peaksin selle lepingu kasutusele võtma, oleks indeksi 0 ja 1 üksused vastavalt õun ja oranž. Piisavalt lihtne.

Mis saab siis, kui ma üritan luua oma ehitaja funktsioonis uue massiivi, mis osutab muutuvmatriisile? Tundub piisavalt lihtne.

ehitaja () avalik {
  ...
  string [] newItems = üksused;
}

Aga oota! saame hoiatuse nagu allpool!

Kas hoiatusest aru saada? Ma ei teinud kumbagi.

Toimuvast täielikuks mõistmiseks laseme arutada, kuidas Solidity tõlgendab mälu vs salvestusruumi.

Salvestusruum vs mälu

Solidity vaatab salvestusruumi ja mälu suhet kahel erineval viisil.

  1. Lepingu riigi andmed
  • ladustamine: muutujad, mis on määratletud lepingu sees kõrgeimal tasemel. (nt üksused)
  • mälu: killud (kui te ei tea, mis on struktuur, vaadake saiti http://solidity.readthedocs.io/et/v0.4.21/types.html)

2. Muutuva väärtuse deklaratsioon

  • Selle stsenaariumi korral saab muutuja väärtuse deklaratsiooni määratleda kui salvestusruumi või mälu sõltuvalt sellest, kuidas soovite selle muutuja salvestada (täpsemalt selgitatakse allpool)

Meie näite jaoks on üksused puuviljalepingu sees olev ladustamisolek. Uue muutujaga newItems on meil kaks võimalust, salvestage muutuja mällu või salvestusruumi. Vaatan allpool üle mõlemad võimalused.

NewItems kui salvestusruum

Kui newItems salvestati salvestusruumina, peate enne newItems sisestama märksõna storage. Allpool toodud näide.

string [] ladustamine newItems = üksused;

Salvestusväärtuse lisamisega peaks hoiatus kaduma. Aga mida see täpselt teeb? Salvestusruumi lisamisega osutavad newItems nüüd üksuste massiivile. Teisisõnu, kõik muudatused, mida teete uutes üksustes, mõjutavad otseselt üksuste massiivi.

pragma kindlus ^ 0.4.17;
leping Viljad {
    nöörid [] avalikud esemed;
    ehitaja () avalik {
        üksused.push ('õun');
        üksused.push ('oranž');
        string [] ladustamine newItems = üksused;
        newItems [1] = 'sidrun';
    }
}
// üksused [1] on nüüd sidrunid
// üksused [0] jäävad samaks kui 'õun'

Kokkuvõtteks sunnib salvestusvõti vastloodud muutuja osutama olekumuutujale (üksustele), mitte koopiale. Uues muutuja mis tahes muudatused muudavad otseselt lepinguriigi muutuja struktuuri.

NewItems kui mälu

newItemsil on püsivusele alternatiivne meetod. Salvestuse asemel on olemas mäluvõimalus. Mäluvalik toimib kursorina, mitte koopiana. Seega EI mõjuta mäluklahvi kasutamine ja mutatsioonide tegemine vastloodud muutujal algset olekumuutujat. Allpool toodud näide.

pragma kindlus ^ 0.4.17;
leping Viljad {
    nöörid [] avalikud esemed;
ehitaja () avalik {
        üksused.push ('õun');
        üksused.push ('oranž');
        string [] mälu newItems = üksused;
        newItems [1] = 'sidrun'
    }
}
// üksused [1] jäävad samaks kui “oranžid”
// üksused [0] jäävad samaks kui 'õun'

Järeldus

Loodan, et see lahendab kõik selle hoiatuse küsimused mälu ja salvestuse kohta. Vaatan salvestust (olekut) kõvakettana ja mälu (kohalikud muutujad, ajutised) RAMina. Kui loodate olekut muutvate funktsioonide loomiseks, võib salvestamine olla parim valik. Kui vajate andmete koopiat, kuid ei pea tingimata lepinguriigiga manipuleerima, kasutage mälu.

Ääremärkus

Lepingufunktsiooni kantud väärtus saadetakse mälu kaudu (vaikimisi). Funktsioon, mis võtab selle parameetri, ei manipuleeri lepingu olekuga. Allpool toodud näide.

pragma kindlus ^ 0.4.17;
leping Viljad {
    nöörid [] avalikud esemed;
    ehitaja () avalik {
        üksused.push ('õun');
        üksused.push ('oranž');
        
        changeFirstElement (üksused);
    }
    
    funktsiooni changeFirstElement (string [] newItems) puhas privaatne {
        newItems [0] = 'sidrun';
    }
}
// üksused [1] jäävad samaks kui “oranžid”
// üksused [0] jäävad samaks kui 'õun'

Kui teil on vaja jõustada oleku muutmist, saate parameetrisse lisada salvestusvõtme.

funktsiooni changeFirstElement (string [] storage newItems) privaatne {
        newItems [0] = 'sidrun';
}

fin