Üdvözöljük a sorozat második részében (az első részt "itt" találja).

Továbbra is megvizsgálunk néhány más rendkívül érdekes drágakövet, amelyeket a "Mutant" használ.

Kezdetben azt terveztem, hogy több gyöngyszemet is lefedek, de miután elkezdtem kutatni az IceNine gyöngyszembe, rájöttem, hogy ez elég nagy egy saját blogbejegyzéshez.

"IceNine"

A IceNine egy könyvtár az objektumok mélyhűtéséhez:

Mire kell ez?

Az elmúlt években a „funkcionális programozás” divattá vált, és hogyan lehet bevezetni olyan nyelveken, amelyek valójában nem működnek, mint a Ruby.

Attól függően, hogy kit kérdezel, mindenki másképp határozza meg, hogy mit jelent a „funkcionális”. Én, két tulajdonságom van, amelyeket alapvetőnek tartok egy funkcionális nyelvhez:

  1. „Tiszta funkciók”
  2. Változhatatlan adatszerkezetek

Úgy gondolom, hogy a Rubynak ebben az értelemben soha nem lesznek tiszta függvényei, de megváltoztathatatlan adatstruktúrákat hozhat létre a Rubyban a freeze meghívásával. Azonban pusztán a freeze meghívása egy objektumon nem fagyasztja le azt, ahogyan azt a fenti kezdeti kódmintában teheti.

És itt jön be a IceNine.

Előfordulhat, hogy a megváltoztathatatlan adatstruktúrák nem alkalmazhatók mindenhol és mindig, de gyakran jelentős előnyöket kínálnak a változtatható adatstruktúrákhoz képest, például:

  • Sokkal könnyebb egy adatszerkezetről okoskodni, ha tudod, hogy mindig garantált állapota lesz
  • Kevésbé hajlamos a hibákra. A legfurcsább hibák gyakran azért fordulnak elő, mert az adatok olyan módon változtak, amit nem is sejtett
  • Könnyebbé teszi a párhuzamos kód írását, mivel a megváltoztathatatlan adatstruktúrák számos gyakori buktatót kiküszöbölnek a párhuzamos kód írása során

Az indoklás nélkül nézzük meg, hogyan működik!

A megfelelő fagyasztó megtalálása

A fenti példámban láthatta, hogy a IceNine használata a következőkre vezethető vissza:

Íme a IceNine modul megfelelő része (a lib/ice_nine.rb-ben van meghatározva):

Rendben, itt nincs sok látnivaló, csak delegálunk IceNine::Freezer-ra (a lib/ice_nine/freezer.rb-ben van meghatározva):

Hagyjuk most figyelmen kívül ezt a rekurziós őrző dolgot – erről később részletesen fogunk beszélni –, és menjünk tovább a spirálon:

Ott van. Itt történik a varázslat.

Boncoljuk ezt a sort:

Először is meg kell értenünk:

A object az az objektum, amelyet az elején átadtunk a IceNine.deep_freeze-nek:

Tehát a object lenne

és így object.class Hash lenne.

És hogy néz ki a [] módszer?

Most kezd érdekessé válni a dolog. Ez a @freezer_cache a fájl tetején van definiálva:

A fenti kód tömör, és sok munkát végez:

  • A @freezer_cache-et hashként állítottuk be. Vegye figyelembe, hogy a @freezer_cache nem egy példányváltozó, hanem egy "osztálypéldányváltozó", ami azt jelenti, hogy ez a hozzárendelés akkor hajtódik végre, amikor a Ruby beolvassa a Freezer osztályt, mivel a Rubys "az osztálytestek végrehajthatók".
  • Elhaladunk egy blokkon a Hash#new felé. Ha olyan kulcsot kérünk a gyorsítótárban, amely nem létezik, ez a blokk a hash objektummal és a kulccsal együtt lesz meghívva, és vissza kell adnia az alapértelmezett értéket (lásd a "Kivonatoló dokumentumok" című részt).
  • Tehát a cache blokkparaméter maga a hash, a mod pedig a IceNine-nak átadott adatstruktúra osztálya, tehát itt Hash.
  • Ezután felfelé haladunk az ősláncon, és keresünk egy megfelelő fagyasztót. Ha ragaszkodunk a hash-példához, azonnal megtaláljuk a IceNine::Freezer::Hash értéket, mivel bármely osztály ősláncának első láncszeme… maga az osztály, ahogy itt látható:

Röviden: Hash adott esetben ez meglepetést okozhat! - Hash fagyasztó. Nyilvánvalóan ez itt a lehető legegyszerűbb példa, mivel sok szélsőséges eset van, ahol ez nem olyan egyszerű. Itt azonban nem megyek bele a részletekbe, és inkább a magas szintre koncentrálok (a find megjelenésének részleteibe sem megyek bele, mivel az egy kicsit bonyolultabb, de megnézheti a lib/ice_nine/freezer-ben).

Most, miután alaposan megértette a fagyasztó keresés működését, térjünk vissza

és főleg:

Mélyhűtő

Ezt most már tudjuk

rész, tehát nézzük azt a részt:

és képzeld el azt

egy IceNine::Freezer::Hash-at adott volna vissza, ahogy a fenti bekezdésben tettük.

Így néz ki a IceNine::Freezer::Hash.guarded_deep_freeze:

Nézzük meg, miről is szól a freeze_key_value_pairs, mielőtt megnéznénk, mi történik a super-on keresztül:

Oké, ez elég egyszerű, nem? Iteráljuk a hash összes kulcsát és értékét, és mélyhűtjük is őket.

Most mi a helyzet super-el?

Ahogy fentebb látható a kezdeti IceNine::Freezer::Hash kódrészletemben, ez az osztály a IceNine::Freezer::Object-tól örökli:

Most már kezdenek értelmet nyerni a dolgok:

  • Ellenőrizzük, hogy a kérdéses objektum támogatja-e a freeze-et, és ha igen, akkor lefagyasztjuk.
  • Ez a legelső példám első részét fedi le
  • Ezután lefagyasztjuk az objektum összes további attribútumait, a Hashay kulcsok és értékek esetén

Oké, akkor most már tudjuk:

  1. hogyan keresnek egy megfelelő fagyasztóosztályt. A fenti példákban a IceNine::Freezer::Hash
  2. hogyan végzi el ez az osztály a tényleges fagyasztást.

Így már csak egy dolgot kell megmagyarázni: mi van ezzel a rekurziós őrrel?

A rekurziós őr

Ha odafigyelt, észrevette, hogy a IceNine rekurzív módon bejár minden olyan adatstruktúrát, amelyet átad.

Ne feledje, hogy így kezdtük IceNine::Freezer-ben:

Ezután újraindítottuk az objektumok osztályának lekérését, a megfelelő fagyasztó meghatározását, lefagyasztását és így tovább a IceNine::Freezer::Hash-ben:

Tehát ott van a rekurzió, amelyet a rekurziós őrön keresztül indítunk el.

Miért van az, hogy „őr”? Mert létrehozhat és átadhat ilyen ciklikus adatstruktúrákat:

Rekurziós védő nélkül IceNine addig ismétlődik, amíg meg nem kapod

Nézzük meg a IceNine::RecursionGuard::ObjectSet(definiálva: lib/ice_nine/support/recursion_guard):

A fenti kód hihetetlenül egyszerű és ugyanakkor hihetetlenül erős.

Először megkapjuk a vizsgált objektum object_id értékét:

Most a fontos rész: Ha már láttuk ezt az objektumot, az azt jelenti, hogy valóban egy ciklikus struktúrán haladunk át. Ebben az esetben csak visszatérünk:

Ha idáig eljutottunk, akkor először látjuk ezt az objektumot, ezért tároljuk' object_id:

És végül engedünk a blokknak:

A deep_freeze elérhetővé tétele minden objektum számára

A IceNine egy alapkiterjesztést is kínál a lib/ice_nine/core_ext/object.rb nyelven:

Először egy külön modult definiálunk, követve azt a konvenciót, hogy az alapvető osztályokba kevert modulok az core_ext hatókörben vannak definiálva. Ez a modul nagyon egyszerű, csak meghívja az IceNine.deep_freeze-t, majd átadja neki az self-t. Mi lesz self? A példánymódszerekkel rendelkező modulok nem használhatók önállóan, csak mixinként. Azt jelenti, osztályba keverve. Tehát az self lesz az az osztály, amelybe kevertük.

Hogyan aktiváljuk ezt?

By

Ez gyakorlatilag elérhetővé teszi a deep_freeze-ot a Ruby objektumterében lévő összes objektum számára.

Egyébként nem számít, hogy ebben az esetben az class_eval vagy instance_eval értéket használja.

Mindkét

és

itt is ugyanaz az eredmény. Ez azonban óriási különbséget jelentene, ha az deep_freeze értéket a Object-on közvetlenül a def-en keresztül határozná meg.

Például. ez

a deep_freeze értéket egy példány szinten határozza meg, mivel a class_eval csak újra megnyitja az osztályt. Szóval jók vagyunk.

Ezt azonban

nem működne, mivel egy egyszeres metódust hozna létre (értsd: osztálymetódus), nem pedig példánymetódusokat.

Tehát tisztában kell lennie ezekkel a különbségekkel. A legtöbb drágakő, amit láttam, használja a Object.instance_eval trükköt a core_ext-hez, és valószínűleg ezt a mintát kell követnie a saját drágaköveinél.

Becsomagolva

Tehát foglaljuk össze, mit tanultunk ma a IceNine-ról:

  • rekurzívan bejár minden olyan adatstruktúrát, amelyen átjut
  • rekurzióvédőt használva, hogy megakadályozza a ciklikus adatstruktúra ismétlődését
  • gyorsítótárazott leképezést tart fenn arról, hogy milyen fagyasztót milyen adattípushoz kell használni
  • lefagyasztja a kapott adatokat
  • majd mélyebbre megy a spirálban minden gyermek számára

A sorozat egy részében ennyi. A következő 3. részben az „Adamantium gem”-et és az „abstract_type gem”-et fogom nézni.