An översikt över blockens exekveringskontext
I den här artikeln kommer vi att undersöka följande ämnen:
- scopes och block
- flat scope guard i klass/modul
Först kan du gärna bläddra bland Scope Gates i Ruby: Del II.
För att börja
Jag är glad att kunna dela med mig av vårt senaste projekt: Fun Facts about Ruby – Volume 1
Varsågod att sprida ordet och dela den här länken! 🙏
Tack för din tid!
I Ruby kan ett block få tillgång till yttre scope
I det här exemplet kan vi få tillgång till variabeln outer_scope_variable
i vårt block. Vårt block får tillgång till variabeln trots att variabeln är deklarerad på en main
-nivå. I det här fallet säger vi att blocket plattar till scopes. Det är därför vi vanligtvis kallar denna mekanism för: Flat Scope.
Å andra sidan skapar blocket ett isolerat scope – även om värdet av self
inom blocket förblir main
-objektet.
Så vi kan inte få tillgång till lokala variabler som definierats inom blocket
Här kan vi inte få tillgång till block_variable
från det yttre scope. Nu när vi är mer bekanta med begreppet flat scope i Ruby ska vi se om detta begrepp påverkar klassdefinitionen.
Klass, modul och block
I Ruby är det man vanligen kallar en klass, bakom scenen, en instans av Class
-klassen
Här skapar vi Hello
– och Greeting
-klasserna på två olika sätt:
- med hjälp av nyckelordet
class
- genom att tilldela en instans av
Class
-klassen tillGreeting
-konstanten
Notera att vi överlämnar ett block till Class.new
-metoden. Detta block kommer att tolkas som klassens innehåll. Normalt kan en klass inte få tillgång till variabler som definierats i det yttre tillämpningsområdet – eftersom nyckelordet class
ändrar värdet på self
och skapar ett isolerat tillämpningsområde.
Så, eftersom vi använder ett block för att skapa vår Greeting
-klass bör vi kunna använda mekanismen för det platta tillämpningsområdet. Verkligen?
Här kan vi se att värdet på self
ändras när vi använder class
eller Class.new
.
Också vårt Class#message
-block är fortfarande isolerat från main
-objektet på grund av användningen av nyckelordet def
. Eftersom vårt block exekveras i kontexten för metoden så har blocket en plattare räckvidd inom detta givna objekt – och inte med en högre räckvidd som main
-objektet.
Det är därför som vi inte har tillgång till outer_variable
inom message
.
Men om vi använder define_method
för att definiera message
så blir räckvidden plattare
Här, eftersom define_method(:message)
tar ett block som argument, blir räckvidden för detta block plattare och denna metod har tillgång till outer_variable
.
Voilà!