Förstå ’själv’ i Ruby
idag skulle jag vilja prata om self
. Om du har programmerat Ruby ett tag har du sannolikt internaliserat tanken på self
. När du läser eller skriver ett program, self
finns det bakom dig.
men för mindre erfarna Rubyister kan self
vara förvirrande. Det förändras alltid, men det visas aldrig uttryckligen i koden. Du förväntas bara veta.
många problem nybörjare möter orsakas av att inte förstå self
. Om du någonsin har” förlorat ” en instansvariabel eller förbryllad över vilka data som är synliga för en mixin, beror det på att du inte förstod self
i det sammanhanget.
i det här inlägget kommer vi att titta på self
i en mängd olika vardagssituationer.
vad är själv?
du kanske har hört folk säga att allt i Ruby är ett objekt. Om det är sant betyder det att varje kod du skriver ”tillhör” något objekt.
self
är en speciell variabel som pekar på objektet som ”äger” den nuvarande exekveringskoden. Ruby använder self
everwhere:
- till exempel variabler:
@myvar
- för metod och konstant sökning
- vid definition av metoder, klasser och moduler.
i teorin är self
ganska uppenbart. Men i praktiken är det lätt för knepiga situationer att dyka upp. Det är därför jag skrev det här inlägget.
exempel på själv
vi kommer att gå igenom flera exempel nu. Om de första verkar för grundläggande för dig, fortsätt bara läsa. De blir mer avancerade.
inuti en instansmetod
i koden nedan är reflect
en instansmetod. Det tillhör objektet Vi skapade via Ghost.new
. Så self
pekar på det objektet.
class Ghost def reflect self endendg = Ghost.newg.reflect == g # => true
inuti en klassmetod
för detta exempel är reflect
en klassmetod av Ghost
. Med klassmetoder ”äger” klassen själv metoden. self
pekar på klassen.
class Ghost def self.reflect self endendGhost.reflect == Ghost # => true
det fungerar på samma sätt med” klass ” metoder inuti moduler. Till exempel:
module Ghost def self.reflect self endend Ghost.reflect == Ghost # => true
kom ihåg att klasser och moduler behandlas som objekt i Ruby. Så detta beteende är inte så annorlunda än det förekomstmetodbeteende vi såg i det första exemplet.
inuti en klass-eller moduldefinition
en funktion i Ruby som gör det så bra för ramar som Rails är att du kan köra godtycklig kod i klass-och moduldefinitioner. När du sätter kod inuti en klass / modul definition, det körs precis som alla andra Ruby kod. Den enda verkliga skillnaden är värdet på self
.
som du kan se nedan, self
pekar på klassen eller modulen som håller på att definieras.
class Ghost self == Ghost # => trueend module Mummy self == Mummy # => trueend
inuti mixin-metoder
blandade metoder beter sig precis som ”normal” instans eller klassmetoder när det gäller self
. Det här är vettigt. Annars skulle mixin inte kunna interagera med den klass du blandade den i.
Instansmetoder
även om reflect
– metoden definierades i modulen är dess self
instansen för den klass den blandades in i.
module Reflection def reflect self endend class Ghost include Reflectionendg = Ghost.newg.reflect == g # => true
klassmetoder
när vi extend
en klass att blanda i klassmetoder, beter sig self
precis som det gör i normala klassmetoder.
module Reflection def reflect self endend class Ghost extend ReflectionendGhost.reflect == Ghost # => true
inuti metaclass
chansen är att du har sett den här populära genvägen för att definiera massor av klassmetoder på en gång.
class Ghost class << self def method1 end def method2 end endend
class << foo
syntaxen är faktiskt ganska intressant. Det låter dig komma åt ett objekts metaklass – som också kallas ”singleton class” eller ”eigenclass.”Jag planerar att täcka metaclasses djupare i ett framtida inlägg. Men för tillfället behöver du bara veta att metaclass är där Ruby lagrar metoder som är unika för ett specifikt objekt.
om du öppnar self
från insidan av class << foo
– blocket får du metaklassen.
class << "test" puts self.inspectend# => #<Class:#<String:0x007f8de283bd88>
utanför någon klass
om du kör kod utanför någon klass, ger Ruby fortfarande self
. Det pekar på ”main”, vilket är en instans av Object
:
puts self.inspect # => main