Kuidas teha rubiinist sügavaid koopiaid

Sageli on vaja teha koopia väärtus rubiinides. Kuigi see võib tunduda lihtne ja see on mõeldud lihtsate objektide jaoks, peate kohe, kui olete andmete koopia teinud struktuuri, millel on mitu objekti või massiivi samal objektil, leiate kiiresti neid palju lõksud.

Objektid ja viited

Toimuva mõistmiseks vaatame mõnda lihtsat koodi. Esiteks sisestage POD-i (tavalised vanad andmed) kasutav määramisoperaator Rubiin.

a = 1
b = a
a + = 1
paneb b

Siin teeb määramisoperaator koopia väärtusest a ja selle määramine b määramisoperaatori kasutamine. Kõik muudatused a ei kajastu b. Aga kuidas oleks millegi keerukamaga? Mõelge sellele.

a = [1,2]
b = a
a << 3
paneb b.inspekti

Enne ülaltoodud programmi käivitamist proovige ära arvata, mis väljund saab ja miks. See ei ole sama, mis eelmises näites, muudatused saidile a kajastuvad b, aga miks? Seda seetõttu, et Massiiv objekt ei ole POD-tüüp. Ülesande operaator ei tee väärtusest koopiat, see kopeerib lihtsalt väärtuse viide objekti Array juurde. a ja b muutujad on nüüd viited sama massiivi objekti jaoks, näevad kummagi muutuja kõik muudatused teises.

instagram viewer

Ja nüüd näete, miks mittetriviaalsete objektide kopeerimine koos viidetega teistele objektidele võib olla keeruline. Kui teete lihtsalt objektist koopia, kopeerite lihtsalt viiteid sügavamatele objektidele, nii et teie koopiat nimetatakse "pinnapealseks koopiaks".

Mida pakub Ruby: dup ja kloon

Ruby pakub objektide koopiate tegemiseks kahte meetodit, sealhulgas ühe, mida saab teha sügavate koopiate tegemiseks. Objekt # dup meetod teeb objektist pinnapealse koopia. Selle saavutamiseks tuleb: dup meetod kutsub lähtesta koopia selle klassi meetod. Mida see täpselt teeb, sõltub klassist. Mõnes klassis, näiteks massiiv, lähtestab see uue massiivi samade liikmetega nagu algne massiiv. See pole siiski sügav koopia. Vaatleme järgmist.

a = [1,2]
b = a.dup
a << 3
paneb b.inspekti
a = [[1,2]]
b = a.dup
a [0] << 3
paneb b.inspekti

Mis siin juhtunud on? Massiiv # lähtesta_kopioon meetod teeb tõepoolest massiivi koopia, kuid see koopia on ise pinnapealne koopia. Kui teie massiivis on muid mitte-POD tüüpe, kasutage dup on ainult osaliselt sügav koopia. See on ainult nii sügav kui esimene massiiv, seda sügavam massiivid, räsi või muud objektid kopeeritakse ainult pinnapealselt.

Mainimist väärib veel üks meetod, kloon. Kloonimeetod teeb sama, mis dup ühe olulise eristusega: eeldatakse, et objektid alistavad selle meetodi ühega, mis võimaldab teha sügavaid koopiaid.

Mida see tegelikult tähendab? See tähendab, et iga teie klass saab määratleda kloonimismeetodi, mis teeb sellest objektist sügava koopia. See tähendab ka, et peate kirjutama kloonimismeetodi iga teie klassi jaoks.

Trikk: marssimine

Objekti marsruutimine on veel üks viis, kuidas öelda objekt seeriaviisiliselt. Teisisõnu, muutke see objekt märgivoogiks, mille saab kirjutada faili, mille saate hiljem sama objekti saamiseks "unmarshal" või "unserialize". Seda saab kasutada mis tahes objekti sügava koopia saamiseks.

a = [[1,2]]
b = marshal.load (marshal.dump (a))
a [0] << 3
paneb b.inspekti

Mis siin juhtunud on? Marssal.dump loob "dump" pesas massiivist, mis on salvestatud a. See prügikott on binaarne tähemärk, mis on ette nähtud faili salvestamiseks. See sisaldab massiivi täielikku sisu, täielikku sügavat koopiat. Järgmine Marssal.koormus teeb vastupidist. See parsib selle binaarse tähemärgi massiivi ja loob täiesti uue massiivi koos täiesti uute massiivi elementidega.

Kuid see on trikk. See on ebaefektiivne, see ei tööta kõigi objektide puhul (mis juhtub, kui proovite sel viisil võrguühendust kloonida?) Ja tõenäoliselt pole see eriti kohutav. Kuid see on lihtsaim viis tavapärasest sügavate koopiate tegemiseks lähtesta koopia või kloon meetodid. Sama saab teha ka selliste meetoditega nagu to_yaml või to_xml kui teil on nende toetamiseks laaditud raamatukogud.

instagram story viewer