Kā izveidot dziļas kopijas rubīnā

Bieži vien ir nepieciešams izgatavot kopiju vērtība rubī. Lai gan tas var šķist vienkāršs un tas ir paredzēts vienkāršiem objektiem, tiklīdz jums ir jāizveido datu kopija struktūra ar vairākiem masīviem vai jaucieniem uz viena un tā paša objekta, jūs ātri atradīsit, ka to ir daudz nekļūdīgi.

Objekti un atsauces

Lai saprastu, kas notiek, apskatīsim dažus vienkāršus kodus. Pirmkārt, piešķiršanas operators, izmantojot POD (Plain Old Data) Rubīns.

a = 1
b = a
a + = 1
liek b

Šeit piešķīruma operators izveido kopiju no vērtības a un piešķirot to b izmantojot uzdevuma operatoru. Visas izmaiņas a netiks atspoguļots b. Bet kā ar kaut ko sarežģītāku? Apsveriet to.

a = [1,2]
b = a
a << 3
liek b.inspektēt

Pirms iepriekš minētās programmas palaišanas mēģiniet uzminēt, kāda būs izvade un kāpēc. Šis nav tas pats, kas iepriekšējais piemērs, veiktās izmaiņas a tiek atspoguļoti b, bet kāpēc? Tas ir tāpēc, ka Masīvs objekts nav POD tips. Piešķiršanas operators neveido vērtības kopiju, tas vienkārši nokopē vērtību atsauce

instagram viewer
objektam Array. a un b mainīgie ir tagad atsauces vienam un tam pašam masīva objektam, jebkuras mainīgās izmaiņas būs redzamas otrā.

Un tagad jūs varat redzēt, kāpēc nav triviālu objektu kopēšana ar atsaucēm uz citiem objektiem var būt sarežģīta. Ja jūs vienkārši izgatavojat objekta kopiju, jūs vienkārši kopējat atsauces uz dziļākiem objektiem, tāpēc jūsu kopija tiek dēvēta par "seklu kopiju".

Ko nodrošina Rubīns: dup un klons

Rubīns nodrošina divas objektu kopiju izgatavošanas metodes, ieskaitot vienu, ko var izgatavot dziļo kopiju veidošanai. Objekts # dup metode veiks objekta seklu kopiju. Lai to sasniegtu, dup metode izsauks sākotnējā_kopija šīs klases metode. Tas, ko tas precīzi dara, ir atkarīgs no klases. Dažās klasēs, piemēram, Masīvs, tas inicializēs jaunu masīvu ar tiem pašiem dalībniekiem kā sākotnējais masīvs. Tomēr šī nav dziļa kopija. Apsveriet sekojošo.

a = [1,2]
b = a.dup
a << 3
liek b.inspektēt
a = [[1,2]]
b = a.dup
a [0] << 3
liek b.inspektēt

Kas te ir noticis? Masīvs # sākotnējā_kopija metode patiešām izveidos masīva kopiju, bet šī kopija pati par sevi ir sekla kopija. Ja masīvā ir kādi citi veidi, kas nav POD, izmantojiet dup būs tikai daļēji dziļa kopija. Tas būs tikai tik dziļš kā pirmais masīvs, bet dziļāks masīvi, hashes vai citi objekti tiks kopēti tikai sekli.

Ir vēl viena pieminēšanas metode, klons. Klona metode dara to pašu, ko dup ar vienu būtisku atšķirību: ir sagaidāms, ka objekti pārsniegs šo metodi ar vienu, kas var veikt dziļas kopijas.

Tātad, ko tas praktiski nozīmē? Tas nozīmē, ka katra no jūsu klasēm var definēt klona metodi, kas izveidos dziļu šī objekta kopiju. Tas arī nozīmē, ka jums ir jāraksta klona metode katrai klasei, kuru veidojat.

Triks: šķirošana

Objekta "šķirošana" ir vēl viens veids, kā pateikt "sērijveida" objektu. Citiem vārdiem sakot, pārvērtiet šo objektu rakstzīmju straumē, ko var rakstīt failā, kuru vēlāk varat "atdarināt" vai "atiestatīt", lai iegūtu to pašu objektu. To var izmantot, lai iegūtu dziļu jebkura objekta kopiju.

a = [[1,2]]
b = Marshal.load (Marshal.dump (a))
a [0] << 3
liek b.inspektēt

Kas te ir noticis? Marshal.dump izveido ligzdota masīva "izgāztuvi", kas glabājas a. Šī izgāztuve ir binārā rakstzīmju virkne, kas paredzēta glabāšanai failā. Tajā ir pilns masīva saturs, pilnīga dziļa kopija. Nākamais, Marshal.load rīkojas tieši pretēji. Tas parsē šo bināro rakstzīmju masīvu un izveido pilnīgi jaunu masīvu ar pilnīgi jauniem masīva elementiem.

Bet tas ir triks. Tas ir neefektīvs, nedarbosies visiem objektiem (kas notiek, ja šādā veidā mēģināt klonēt tīkla savienojumu?), Un tas, iespējams, nav briesmīgi ātrs. Tomēr tas ir vienkāršākais veids, kā izveidot dziļas kopijas, kas neatbilst pasūtījumam sākotnējā_kopija vai klons metodes. To pašu var izdarīt arī ar tādām metodēm kā to_yaml vai līdz_xml ja jums ir ielādētas bibliotēkas to atbalstam.

instagram story viewer