Kaip pasidaryti gilias kopijas „Ruby“

Dažnai reikia pasidaryti a kopiją vertė rubine. Nors tai gali atrodyti paprasta ir skirta paprastiems objektams, kai tik turite pasidaryti duomenų kopiją struktūrą su daugybe masyvų ar maišos tame pačiame objekte, greitai rasite daug spąstus.

Objektai ir literatūros sąrašas

Norėdami suprasti, kas vyksta, pažvelkime į paprastą kodą. Pirmiausia priskyrimo operatorius, naudojantis POD (Plain Old Data), įveda Rubinas.

a = 1
b = a
a + = 1
kelia b

Čia priskyrimo operatorius padaro vertės vertę a ir priskiriant tai b naudojant priskyrimo operatorių. Bet kokie pakeitimai a nebus atspindėta b. O kaip kažkas sudėtingesnio? Apsvarstykite tai.

a = [1,2]
b = a
a << 3
kelia b.svarstyti

Prieš paleisdami aukščiau pateiktą programą, pabandykite atspėti, koks bus išėjimas ir kodėl. Tai nėra tas pats kaip ankstesnis pavyzdys, pakeitimai padaryti a atsispindi b, bet kodėl? Taip yra todėl, kad Masyvas objektas nėra POD tipas. Priskyrimo operatorius negamina vertės kopijos, ji tiesiog nukopijuoja vertę nuoroda į Array objektą.

instagram viewer
a ir b kintamieji yra dabar nuorodos tame pačiame masyvo objekte, bet kurio kintamojo pasikeitimai bus matomi kitame.

Ir dabar jūs galite suprasti, kodėl nesudėtinga kopijuoti ne trivialius objektus su nuorodomis į kitus objektus gali būti sudėtinga. Jei tiesiog padarote objekto kopiją, jūs tiesiog nukopijuojate nuorodas į gilesnius objektus, taigi jūsų kopija yra vadinama „seklia kopija“.

Ką teikia „Ruby“: dupas ir klonas

„Ruby“ siūlo du objektų kopijų darymo būdus, įskaitant vieną, kurį galima pasidaryti giliai. Objektas # dup metodas padarys negilią objekto kopiją. Norėdami tai pasiekti, dup metodas vadins inicijuoti_kopiją tos klasės metodas. Ką tai tiksliai daro, priklauso nuo klasės. Kai kuriose klasėse, tokiose kaip masyvas, jis inicijuos naują masyvą su tais pačiais nariais kaip ir pradinis masyvas. Tačiau tai nėra gilus egzempliorius. Apsvarstykite šiuos dalykus.

a = [1,2]
b = a.dup
a << 3
kelia b.svarstyti
a = [[1,2]]
b = a.dup
a [0] << 3
kelia b.svarstyti

Kas čia nutiko? Masyvas # pradinis_kopija Metodas iš tikrųjų padarys masyvo kopiją, tačiau pati kopija yra sekli. Jei savo masyve turite kitų ne POD tipų, naudokite dup bus tik iš dalies gilus egzempliorius. Jis bus tik toks gilus kaip pirmasis masyvas, bet gilesnis masyvai, maišos ar kiti objektai bus kopijuojami tik negiliai.

Yra dar vienas metodas, kurį verta paminėti, klonas. Klono metodas daro tą patį, ką ir dup su vienu svarbiu išskirtinumu: tikimasi, kad objektai šį metodą pakeis tuo, kuris gali padaryti gilumines kopijas.

Taigi, ką tai reiškia praktiškai? Tai reiškia, kad kiekviena iš jūsų klasių gali apibrėžti klono metodą, kuris padarys gilią to objekto kopiją. Tai taip pat reiškia, kad jūs turite parašyti klono metodą kiekvienai klasei.

Triukas: maršavimas

Objekto „pažymėjimas“ yra dar vienas būdas pasakyti „serijinį“ objektą. Kitaip tariant, paverskite tą objektą simbolių srautu, kurį galima įrašyti į failą, kurį vėliau galėsite „unmarshal“ arba „unserialize“, kad gautumėte tą patį objektą. Tai galima išnaudoti norint gauti gilią bet kurio objekto kopiją.

a = [[1,2]]
b = „Marshal.load“ („Marshal.dump (a)“)
a [0] << 3
kelia b.svarstyti

Kas čia nutiko? Maršalas.dump sukuria įdėto masyvo, esančio a. Ši nuoroda yra dvejetainė simbolių eilutė, skirta saugoti faile. Jame yra visas masyvo turinys, išsami gilioji kopija. Kitas, Maršalas.krauti elgiasi priešingai. Jis išanalizuoja šį dvejetainį simbolių masyvą ir sukuria visiškai naują masyvą su visiškai naujais masyvo elementais.

Bet tai yra triukas. Tai neveiksminga, jis neveiks visų objektų (kas nutiks, jei tokiu būdu bandysite klonuoti tinklo ryšį?) Ir greičiausiai tai nėra baisiai greita. Tačiau tai yra lengviausias būdas padaryti gilumines kopijas, neįprastas inicijuoti_kopiją arba klonas metodai. Be to, tą patį galima padaryti ir tokiais metodais kaip to_yaml arba to_xml jei turite įkeltas bibliotekas joms palaikyti.