Forståelse ‘selv’ i Ruby
i dag vil jeg gerne tale om self
. Hvis du har programmeret Ruby i et stykke tid, har du sandsynligvis internaliseret ideen om self
. Når du læser eller skriver et program, self
er der i baghovedet.
men for mindre erfarne Rubyister kan self
være forvirrende. Det ændrer sig altid, men det vises aldrig eksplicit i koden. Du forventes bare at vide det.
mange af de problemer, begyndere står overfor, skyldes ikke forståelse self
. Hvis du nogensinde har “mistet” en instansvariabel eller forvirret over, hvilke data der er synlige for en blanding, så er det fordi du ikke forstod self
i den sammenhæng.
i dette indlæg skal vi se på self
i en række hverdagssituationer.
Hvad er selv?
du har måske hørt folk sige, at alt i Ruby er et objekt. Hvis det er sandt, betyder det, at hvert stykke kode, du skriver, “tilhører” et objekt.
self
er en speciel variabel, der peger på det objekt, der “ejer” den aktuelt udførte kode. Ruby bruger self
overalt:
- for eksempel variabler:
@myvar
- til metode og konstant opslag
- ved definition af metoder, klasser og moduler.
i teorien er self
ret indlysende. Men i praksis er det let for vanskelige situationer at dukke op. Derfor skrev jeg dette indlæg.
eksempler på selv
vi vil gennemgå flere eksempler nu. Hvis de første virker for grundlæggende for dig, skal du bare fortsætte med at læse. De bliver mere avancerede.
inde i en instansmetode
i koden nedenfor er reflect
en instansmetode. Det tilhører det objekt, vi oprettede via Ghost.new
. Så self
peger på dette objekt.
class Ghost def reflect self endendg = Ghost.newg.reflect == g # => true
inde i en klassemetode
i dette eksempel er reflect
en klassemetode på Ghost
. Med klassemetoder “ejer” klassen selv metoden. self
peger på klassen.
class Ghost def self.reflect self endendGhost.reflect == Ghost # => true
det fungerer det samme med” klasse ” metoder inde i moduler. For eksempel:
module Ghost def self.reflect self endend Ghost.reflect == Ghost # => true
husk, klasser og moduler behandles som objekter i Ruby. Så denne adfærd er ikke så forskellig fra den forekomstmetode, vi så i det første eksempel.
inde i en klasse-eller moduldefinition
et træk ved Ruby, der gør det så godt egnet til rammer som Rails, er, at du kan udføre vilkårlig kode inde i klasse-og moduldefinitioner. Når du sætter kode inde i en klasse / modul definition, det kører ligesom enhver anden Ruby kode. Den eneste reelle forskel er værdien af self
.
som du kan se nedenfor, self
peger på den klasse eller det modul, der er ved at blive defineret.
class Ghost self == Ghost # => trueend module Mummy self == Mummy # => trueend
indenfor blandingsmetoder
blandede metoder opfører sig ligesom “normale” instanseller klassemetoder, når det kommer til self
. Det giver mening. Ellers ville blandingen ikke være i stand til at interagere med den klasse, du blandede den i.
Instansmetoder
selvom reflect
– metoden blev defineret i modulet, er dens self
forekomsten af den klasse, den blev blandet ind i.
module Reflection def reflect self endend class Ghost include Reflectionendg = Ghost.newg.reflect == g # => true
klassemetoder
når vi extend
en klasse, der skal blandes i klassemetoder, opfører self
sig nøjagtigt som det gør i normale klassemetoder.
module Reflection def reflect self endend class Ghost extend ReflectionendGhost.reflect == Ghost # => true
inde i metaklassen
chancerne er, at du har set denne populære genvej til at definere mange klassemetoder på en gang.
class Ghost class << self def method1 end def method2 end endend
syntaksen class << foo
er faktisk ret interessant. Det giver dig adgang til et objekts metaklasse-som også kaldes “singleton class” eller “eigenclass.”Jeg planlægger at dække metaclasses dybere i et fremtidigt indlæg. Men for nu skal du bare vide, at metaklassen er, hvor Ruby gemmer metoder, der er unikke for et bestemt objekt.
hvis du åbner self
inde fra class << foo
– blokken, får du metaklassen.
class << "test" puts self.inspectend# => #<Class:#<String:0x007f8de283bd88>
uden for enhver klasse
hvis du kører kode uden for en klasse, giver Ruby stadig self
. Det peger på “main”, som er en forekomst af Object
:
puts self.inspect # => main